[fiona] 01/12: Add patch for GDAL 2.0 support.

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sun Feb 7 22:37:33 UTC 2016


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

sebastic pushed a commit to branch master
in repository fiona.

commit cc9ed6b6388f0906f4345d0770027efaa00db559
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Oct 23 21:51:25 2015 +0200

    Add patch for GDAL 2.0 support.
---
 debian/changelog                   |    7 +
 debian/patches/0003-GDAL-2.0.patch | 4432 ++++++++++++++++++++++++++++++++++++
 debian/patches/series              |    1 +
 3 files changed, 4440 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 02011be..c069b65 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+fiona (1.6.2-2) UNRELEASED; urgency=medium
+
+  * Team upload.
+  * Add patch for GDAL 2.0 support.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Fri, 23 Oct 2015 21:50:46 +0200
+
 fiona (1.6.2-1) unstable; urgency=medium
 
   * Imported Upstream version 1.6.2
diff --git a/debian/patches/0003-GDAL-2.0.patch b/debian/patches/0003-GDAL-2.0.patch
new file mode 100644
index 0000000..5563b0c
--- /dev/null
+++ b/debian/patches/0003-GDAL-2.0.patch
@@ -0,0 +1,4432 @@
+Origin: https://github.com/Toblerity/Fiona/pull/275
+Bug: https://github.com/Toblerity/Fiona/issues/239
+Bug-Debian: https://bugs.debian.org/802808
+
+From 84e7ce2786e3d881d0a88156bb1e26167bb2ce0d Mon Sep 17 00:00:00 2001
+From: Rene Buffat <buffat at gmail.com>
+Date: Wed, 23 Sep 2015 22:40:37 +0200
+Subject: [PATCH 01/10] sperate implementation for gdal2
+
+---
+ .travis.yml       |    2 +-
+ fiona/ograpi.pxd  |  145 --
+ fiona/ograpi1.pxd |  145 ++
+ fiona/ograpi2.pxd |  183 ++
+ fiona/ogrext.pyx  | 1233 -----------
+ fiona/ogrext1.pyx | 1233 +++++++++++
+ fiona/ogrext2.pyx | 6240 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ setup.py          |   14 +-
+ 8 files changed, 7814 insertions(+), 1381 deletions(-)
+ delete mode 100644 fiona/ograpi.pxd
+ create mode 100644 fiona/ograpi1.pxd
+ create mode 100644 fiona/ograpi2.pxd
+ delete mode 100644 fiona/ogrext.pyx
+ create mode 100644 fiona/ogrext1.pyx
+ create mode 100644 fiona/ogrext2.pyx
+
+--- a/.travis.yml
++++ b/.travis.yml
+@@ -8,6 +8,7 @@ before_install:
+   - sudo apt-get update -qq
+   - sudo apt-get install -y libgdal1h gdal-bin libgdal-dev
+ install:
++  - "pip install -r requirements.txt"
+   - "pip install -r requirements-dev.txt"
+   - "pip install pytest"
+   - "pip install coveralls"
+--- a/fiona/ograpi.pxd
++++ /dev/null
+@@ -1,145 +0,0 @@
+-# Copyright (c) 2007, Sean C. Gillies
+-# All rights reserved.
+-# See ../LICENSE.txt
+-
+-cdef extern from "gdal.h":
+-    char * GDALVersionInfo (char *pszRequest)
+-
+-cdef extern from "gdal_version.h":
+-    int    GDAL_COMPUTE_VERSION(int maj, int min, int rev)
+-
+-cdef extern from "cpl_conv.h":
+-    void *  CPLMalloc (size_t)
+-    void    CPLFree (void *ptr)
+-    void    CPLSetThreadLocalConfigOption (char *key, char *val)
+-    const char *CPLGetConfigOption (char *, char *)
+-
+-cdef extern from "cpl_string.h":
+-    char ** CSLSetNameValue (char **list, char *name, char *value)
+-    void    CSLDestroy (char **list)
+-
+-cdef extern from "cpl_vsi.h":
+-    ctypedef struct VSILFILE:
+-        pass
+-    int VSIFCloseL (VSILFILE *)
+-    VSILFILE * VSIFileFromMemBuffer (const char * filename,
+-                                     unsigned char * data,
+-                                     int data_len,
+-                                     int take_ownership)
+-    int VSIUnlink (const char * pathname)
+-
+-ctypedef int OGRErr
+-ctypedef struct OGREnvelope:
+-    double MinX
+-    double MaxX
+-    double MinY
+-    double MaxY
+-
+-cdef extern from "ogr_core.h":
+-    char *  OGRGeometryTypeToName(int)
+-
+-cdef extern from "ogr_srs_api.h":
+-    void    OSRCleanup ()
+-    void *  OSRClone (void *srs)
+-    void    OSRDestroySpatialReference (void *srs)
+-    int     OSRExportToProj4 (void *srs, char **params)
+-    int     OSRExportToWkt (void *srs, char **params)
+-    int     OSRImportFromEPSG (void *srs, int code)
+-    int     OSRImportFromProj4 (void *srs, char *proj)
+-    int     OSRSetFromUserInput (void *srs, char *input)
+-    int     OSRAutoIdentifyEPSG (void *srs)
+-    int     OSRFixup(void *srs)
+-    const char * OSRGetAuthorityName (void *srs, const char *key)
+-    const char * OSRGetAuthorityCode (void *srs, const char *key)
+-    void *  OSRNewSpatialReference (char *wkt)
+-    void    OSRRelease (void *srs)
+-    void *  OCTNewCoordinateTransformation (void *source, void *dest)
+-    void    OCTDestroyCoordinateTransformation (void *source)
+-    int     OCTTransform (void *ct, int nCount, double *x, double *y, double *z)
+-
+-cdef extern from "ogr_api.h":
+-    char *  OGR_Dr_GetName (void *driver)
+-    void *  OGR_Dr_CreateDataSource (void *driver, const char *path, char **options)
+-    int     OGR_Dr_DeleteDataSource (void *driver, char *)
+-    void *  OGR_Dr_Open (void *driver, const char *path, int bupdate)
+-    int     OGR_DS_DeleteLayer (void *datasource, int n)
+-    void *  OGR_DS_CreateLayer (void *datasource, char *name, void *crs, int geomType, char **options)
+-    void *  OGR_DS_ExecuteSQL (void *datasource, char *name, void *filter, char *dialext)
+-    void    OGR_DS_Destroy (void *datasource)
+-    void *  OGR_DS_GetDriver (void *layer_defn)
+-    void *  OGR_DS_GetLayerByName (void *datasource, char *name)
+-    int     OGR_DS_GetLayerCount (void *datasource)
+-    void *  OGR_DS_GetLayer (void *datasource, int n)
+-    void    OGR_DS_ReleaseResultSet (void *datasource, void *results)
+-    int     OGR_DS_SyncToDisk (void *datasource)
+-    void *  OGR_F_Create (void *featuredefn)
+-    void    OGR_F_Destroy (void *feature)
+-    long    OGR_F_GetFID (void *feature)
+-    int     OGR_F_IsFieldSet (void *feature, int n)
+-    int     OGR_F_GetFieldAsDateTime (void *feature, int n, int *y, int *m, int *d, int *h, int *m, int *s, int *z)
+-    double  OGR_F_GetFieldAsDouble (void *feature, int n)
+-    int     OGR_F_GetFieldAsInteger (void *feature, int n)
+-    char *  OGR_F_GetFieldAsString (void *feature, int n)
+-    int     OGR_F_GetFieldCount (void *feature)
+-    void *  OGR_F_GetFieldDefnRef (void *feature, int n)
+-    int     OGR_F_GetFieldIndex (void *feature, char *name)
+-    void *  OGR_F_GetGeometryRef (void *feature)
+-    void    OGR_F_SetFieldDateTime (void *feature, int n, int y, int m, int d, int hh, int mm, int ss, int tz)
+-    void    OGR_F_SetFieldDouble (void *feature, int n, double value)
+-    void    OGR_F_SetFieldInteger (void *feature, int n, int value)
+-    void    OGR_F_SetFieldString (void *feature, int n, char *value)
+-    int     OGR_F_SetGeometryDirectly (void *feature, void *geometry)
+-    void *  OGR_FD_Create (char *name)
+-    int     OGR_FD_GetFieldCount (void *featuredefn)
+-    void *  OGR_FD_GetFieldDefn (void *featuredefn, int n)
+-    int     OGR_FD_GetGeomType (void *featuredefn)
+-    char *  OGR_FD_GetName (void *featuredefn)
+-    void *  OGR_Fld_Create (char *name, int fieldtype)
+-    void    OGR_Fld_Destroy (void *fielddefn)
+-    char *  OGR_Fld_GetNameRef (void *fielddefn)
+-    int     OGR_Fld_GetPrecision (void *fielddefn)
+-    int     OGR_Fld_GetType (void *fielddefn)
+-    int     OGR_Fld_GetWidth (void *fielddefn)
+-    void    OGR_Fld_Set (void *fielddefn, char *name, int fieldtype, int width, int precision, int justification)
+-    void    OGR_Fld_SetPrecision (void *fielddefn, int n)
+-    void    OGR_Fld_SetWidth (void *fielddefn, int n)
+-    OGRErr  OGR_G_AddGeometryDirectly (void *geometry, void *part)
+-    void    OGR_G_AddPoint (void *geometry, double x, double y, double z)
+-    void    OGR_G_AddPoint_2D (void *geometry, double x, double y)
+-    void    OGR_G_CloseRings (void *geometry)
+-    void *  OGR_G_CreateGeometry (int wkbtypecode)
+-    void    OGR_G_DestroyGeometry (void *geometry)
+-    unsigned char *  OGR_G_ExportToJson (void *geometry)
+-    void    OGR_G_ExportToWkb (void *geometry, int endianness, char *buffer)
+-    int     OGR_G_GetCoordinateDimension (void *geometry)
+-    int     OGR_G_GetGeometryCount (void *geometry)
+-    unsigned char *  OGR_G_GetGeometryName (void *geometry)
+-    int     OGR_G_GetGeometryType (void *geometry)
+-    void *  OGR_G_GetGeometryRef (void *geometry, int n)
+-    int     OGR_G_GetPointCount (void *geometry)
+-    double  OGR_G_GetX (void *geometry, int n)
+-    double  OGR_G_GetY (void *geometry, int n)
+-    double  OGR_G_GetZ (void *geometry, int n)
+-    void    OGR_G_ImportFromWkb (void *geometry, unsigned char *bytes, int nbytes)
+-    int     OGR_G_WkbSize (void *geometry)
+-    OGRErr  OGR_L_CreateFeature (void *layer, void *feature)
+-    int     OGR_L_CreateField (void *layer, void *fielddefn, int flexible)
+-    OGRErr  OGR_L_GetExtent (void *layer, void *extent, int force)
+-    void *  OGR_L_GetFeature (void *layer, int n)
+-    int     OGR_L_GetFeatureCount (void *layer, int m)
+-    void *  OGR_L_GetLayerDefn (void *layer)
+-    char *  OGR_L_GetName (void *layer)
+-    void *  OGR_L_GetNextFeature (void *layer)
+-    void *  OGR_L_GetSpatialFilter (void *layer)
+-    void *  OGR_L_GetSpatialRef (void *layer)
+-    void    OGR_L_ResetReading (void *layer)
+-    void    OGR_L_SetSpatialFilter (void *layer, void *geometry)
+-    void    OGR_L_SetSpatialFilterRect (
+-                void *layer, double minx, double miny, double maxx, double maxy
+-                )
+-    int     OGR_L_TestCapability (void *layer, char *name)
+-    void *  OGRGetDriverByName (char *)
+-    void *  OGROpen (char *path, int mode, void *x)
+-    void *  OGROpenShared (char *path, int mode, void *x)
+-    int     OGRReleaseDataSource (void *datasource)
+-    OGRErr  OGR_L_SetNextByIndex (void *layer, long nIndex)
+--- /dev/null
++++ b/fiona/ograpi1.pxd
+@@ -0,0 +1,145 @@
++# Copyright (c) 2007, Sean C. Gillies
++# All rights reserved.
++# See ../LICENSE.txt
++
++cdef extern from "gdal.h":
++    char * GDALVersionInfo (char *pszRequest)
++
++cdef extern from "gdal_version.h":
++    int    GDAL_COMPUTE_VERSION(int maj, int min, int rev)
++
++cdef extern from "cpl_conv.h":
++    void *  CPLMalloc (size_t)
++    void    CPLFree (void *ptr)
++    void    CPLSetThreadLocalConfigOption (char *key, char *val)
++    const char *CPLGetConfigOption (char *, char *)
++
++cdef extern from "cpl_string.h":
++    char ** CSLSetNameValue (char **list, char *name, char *value)
++    void    CSLDestroy (char **list)
++
++cdef extern from "cpl_vsi.h":
++    ctypedef struct VSILFILE:
++        pass
++    int VSIFCloseL (VSILFILE *)
++    VSILFILE * VSIFileFromMemBuffer (const char * filename,
++                                     unsigned char * data,
++                                     int data_len,
++                                     int take_ownership)
++    int VSIUnlink (const char * pathname)
++
++ctypedef int OGRErr
++ctypedef struct OGREnvelope:
++    double MinX
++    double MaxX
++    double MinY
++    double MaxY
++
++cdef extern from "ogr_core.h":
++    char *  OGRGeometryTypeToName(int)
++
++cdef extern from "ogr_srs_api.h":
++    void    OSRCleanup ()
++    void *  OSRClone (void *srs)
++    void    OSRDestroySpatialReference (void *srs)
++    int     OSRExportToProj4 (void *srs, char **params)
++    int     OSRExportToWkt (void *srs, char **params)
++    int     OSRImportFromEPSG (void *srs, int code)
++    int     OSRImportFromProj4 (void *srs, char *proj)
++    int     OSRSetFromUserInput (void *srs, char *input)
++    int     OSRAutoIdentifyEPSG (void *srs)
++    int     OSRFixup(void *srs)
++    const char * OSRGetAuthorityName (void *srs, const char *key)
++    const char * OSRGetAuthorityCode (void *srs, const char *key)
++    void *  OSRNewSpatialReference (char *wkt)
++    void    OSRRelease (void *srs)
++    void *  OCTNewCoordinateTransformation (void *source, void *dest)
++    void    OCTDestroyCoordinateTransformation (void *source)
++    int     OCTTransform (void *ct, int nCount, double *x, double *y, double *z)
++
++cdef extern from "ogr_api.h":
++    char *  OGR_Dr_GetName (void *driver)
++    void *  OGR_Dr_CreateDataSource (void *driver, const char *path, char **options)
++    int     OGR_Dr_DeleteDataSource (void *driver, char *)
++    void *  OGR_Dr_Open (void *driver, const char *path, int bupdate)
++    int     OGR_DS_DeleteLayer (void *datasource, int n)
++    void *  OGR_DS_CreateLayer (void *datasource, char *name, void *crs, int geomType, char **options)
++    void *  OGR_DS_ExecuteSQL (void *datasource, char *name, void *filter, char *dialext)
++    void    OGR_DS_Destroy (void *datasource)
++    void *  OGR_DS_GetDriver (void *layer_defn)
++    void *  OGR_DS_GetLayerByName (void *datasource, char *name)
++    int     OGR_DS_GetLayerCount (void *datasource)
++    void *  OGR_DS_GetLayer (void *datasource, int n)
++    void    OGR_DS_ReleaseResultSet (void *datasource, void *results)
++    int     OGR_DS_SyncToDisk (void *datasource)
++    void *  OGR_F_Create (void *featuredefn)
++    void    OGR_F_Destroy (void *feature)
++    long    OGR_F_GetFID (void *feature)
++    int     OGR_F_IsFieldSet (void *feature, int n)
++    int     OGR_F_GetFieldAsDateTime (void *feature, int n, int *y, int *m, int *d, int *h, int *m, int *s, int *z)
++    double  OGR_F_GetFieldAsDouble (void *feature, int n)
++    int     OGR_F_GetFieldAsInteger (void *feature, int n)
++    char *  OGR_F_GetFieldAsString (void *feature, int n)
++    int     OGR_F_GetFieldCount (void *feature)
++    void *  OGR_F_GetFieldDefnRef (void *feature, int n)
++    int     OGR_F_GetFieldIndex (void *feature, char *name)
++    void *  OGR_F_GetGeometryRef (void *feature)
++    void    OGR_F_SetFieldDateTime (void *feature, int n, int y, int m, int d, int hh, int mm, int ss, int tz)
++    void    OGR_F_SetFieldDouble (void *feature, int n, double value)
++    void    OGR_F_SetFieldInteger (void *feature, int n, int value)
++    void    OGR_F_SetFieldString (void *feature, int n, char *value)
++    int     OGR_F_SetGeometryDirectly (void *feature, void *geometry)
++    void *  OGR_FD_Create (char *name)
++    int     OGR_FD_GetFieldCount (void *featuredefn)
++    void *  OGR_FD_GetFieldDefn (void *featuredefn, int n)
++    int     OGR_FD_GetGeomType (void *featuredefn)
++    char *  OGR_FD_GetName (void *featuredefn)
++    void *  OGR_Fld_Create (char *name, int fieldtype)
++    void    OGR_Fld_Destroy (void *fielddefn)
++    char *  OGR_Fld_GetNameRef (void *fielddefn)
++    int     OGR_Fld_GetPrecision (void *fielddefn)
++    int     OGR_Fld_GetType (void *fielddefn)
++    int     OGR_Fld_GetWidth (void *fielddefn)
++    void    OGR_Fld_Set (void *fielddefn, char *name, int fieldtype, int width, int precision, int justification)
++    void    OGR_Fld_SetPrecision (void *fielddefn, int n)
++    void    OGR_Fld_SetWidth (void *fielddefn, int n)
++    OGRErr  OGR_G_AddGeometryDirectly (void *geometry, void *part)
++    void    OGR_G_AddPoint (void *geometry, double x, double y, double z)
++    void    OGR_G_AddPoint_2D (void *geometry, double x, double y)
++    void    OGR_G_CloseRings (void *geometry)
++    void *  OGR_G_CreateGeometry (int wkbtypecode)
++    void    OGR_G_DestroyGeometry (void *geometry)
++    unsigned char *  OGR_G_ExportToJson (void *geometry)
++    void    OGR_G_ExportToWkb (void *geometry, int endianness, char *buffer)
++    int     OGR_G_GetCoordinateDimension (void *geometry)
++    int     OGR_G_GetGeometryCount (void *geometry)
++    unsigned char *  OGR_G_GetGeometryName (void *geometry)
++    int     OGR_G_GetGeometryType (void *geometry)
++    void *  OGR_G_GetGeometryRef (void *geometry, int n)
++    int     OGR_G_GetPointCount (void *geometry)
++    double  OGR_G_GetX (void *geometry, int n)
++    double  OGR_G_GetY (void *geometry, int n)
++    double  OGR_G_GetZ (void *geometry, int n)
++    void    OGR_G_ImportFromWkb (void *geometry, unsigned char *bytes, int nbytes)
++    int     OGR_G_WkbSize (void *geometry)
++    OGRErr  OGR_L_CreateFeature (void *layer, void *feature)
++    int     OGR_L_CreateField (void *layer, void *fielddefn, int flexible)
++    OGRErr  OGR_L_GetExtent (void *layer, void *extent, int force)
++    void *  OGR_L_GetFeature (void *layer, int n)
++    int     OGR_L_GetFeatureCount (void *layer, int m)
++    void *  OGR_L_GetLayerDefn (void *layer)
++    char *  OGR_L_GetName (void *layer)
++    void *  OGR_L_GetNextFeature (void *layer)
++    void *  OGR_L_GetSpatialFilter (void *layer)
++    void *  OGR_L_GetSpatialRef (void *layer)
++    void    OGR_L_ResetReading (void *layer)
++    void    OGR_L_SetSpatialFilter (void *layer, void *geometry)
++    void    OGR_L_SetSpatialFilterRect (
++                void *layer, double minx, double miny, double maxx, double maxy
++                )
++    int     OGR_L_TestCapability (void *layer, char *name)
++    void *  OGRGetDriverByName (char *)
++    void *  OGROpen (char *path, int mode, void *x)
++    void *  OGROpenShared (char *path, int mode, void *x)
++    int     OGRReleaseDataSource (void *datasource)
++    OGRErr  OGR_L_SetNextByIndex (void *layer, long nIndex)
+--- /dev/null
++++ b/fiona/ograpi2.pxd
+@@ -0,0 +1,185 @@
++# Copyright (c) 2007, Sean C. Gillies
++# All rights reserved.
++# See ../LICENSE.txt
++
++cdef extern from "gdal.h":
++    char * GDALVersionInfo (char *pszRequest)
++    void * GDALGetDriverByName(const char * pszName)
++    void * GDALOpenEx(const char * pszFilename,
++                      unsigned int nOpenFlags,
++                      const char ** papszAllowedDrivers,
++                      const char ** papszOpenOptions,
++                      const char *const *papszSibling1Files
++                      )
++    int GDAL_OF_UPDATE
++    int GDAL_OF_READONLY
++    int GDAL_OF_VECTOR
++    int GDAL_OF_VERBOSE_ERROR
++    int GDALDatasetGetLayerCount(void * hds)
++    void * GDALDatasetGetLayer(void * hDS, int iLayer)
++    void * GDALDatasetGetLayerByName(void * hDS, char * pszName)
++    void GDALClose(void * hDS)
++    void * GDALGetDatasetDriver(void * hDataset)
++    void * GDALCreate(void * hDriver,
++                      const char * pszFilename,
++                      int nXSize,
++                      int     nYSize,
++                      int     nBands,
++                      GDALDataType eBandType,
++                      char ** papszOptions)
++    void * GDALDatasetCreateLayer(void * hDS,
++                                  const char * pszName,
++                                  void * hSpatialRef,
++                                  int eType,
++                                  char ** papszOptions)
++    int GDALDatasetDeleteLayer(void * hDS, int iLayer)
++    void GDALFlushCache(void * hDS)
++    char * GDALGetDriverShortName(void * hDriver)
++    char * GDALGetDatasetDriver (void * hDataset)
++
++
++    ctypedef enum GDALDataType:
++        GDT_Unknown
++        GDT_Byte
++        GDT_UInt16
++        GDT_Int16
++        GDT_UInt32
++        GDT_Int32
++        GDT_Float32
++        GDT_Float64
++        GDT_CInt16
++        GDT_CInt32
++        GDT_CFloat32
++        GDT_CFloat64
++        GDT_TypeCount
++
++cdef extern from "gdal_version.h":
++    int    GDAL_COMPUTE_VERSION(int maj, int min, int rev)
++
++cdef extern from "cpl_conv.h":
++    void *  CPLMalloc (size_t)
++    void    CPLFree (void *ptr)
++    void    CPLSetThreadLocalConfigOption (char *key, char *val)
++    const char *CPLGetConfigOption (char *, char *)
++
++cdef extern from "cpl_string.h":
++    char ** CSLSetNameValue (char **list, char *name, char *value)
++    void    CSLDestroy (char **list)
++
++cdef extern from "cpl_vsi.h":
++    ctypedef struct VSILFILE:
++        pass
++    int VSIFCloseL (VSILFILE *)
++    VSILFILE * VSIFileFromMemBuffer (const char * filename,
++                                     unsigned char * data,
++                                     int data_len,
++                                     int take_ownership)
++    int VSIUnlink (const char * pathname)
++
++ctypedef int OGRErr
++ctypedef struct OGREnvelope:
++    double MinX
++    double MaxX
++    double MinY
++    double MaxY
++
++cdef extern from "ogr_core.h":
++    char *  OGRGeometryTypeToName(int)
++
++cdef extern from "ogr_srs_api.h":
++    void    OSRCleanup ()
++    void *  OSRClone (void *srs)
++    void    OSRDestroySpatialReference (void *srs)
++    int     OSRExportToProj4 (void *srs, char **params)
++    int     OSRExportToWkt (void *srs, char **params)
++    int     OSRImportFromEPSG (void *srs, int code)
++    int     OSRImportFromProj4 (void *srs, char *proj)
++    int     OSRSetFromUserInput (void *srs, char *input)
++    int     OSRAutoIdentifyEPSG (void *srs)
++    int     OSRFixup(void *srs)
++    const char * OSRGetAuthorityName (void *srs, const char *key)
++    const char * OSRGetAuthorityCode (void *srs, const char *key)
++    void *  OSRNewSpatialReference (char *wkt)
++    void    OSRRelease (void *srs)
++    void *  OCTNewCoordinateTransformation (void *source, void *dest)
++    void    OCTDestroyCoordinateTransformation (void *source)
++    int     OCTTransform (void *ct, int nCount, double *x, double *y, double *z)
++
++cdef extern from "ogr_api.h":
++    char *  OGR_Dr_GetName (void *driver)
++    void *  OGR_Dr_CreateDataSource (void *driver, const char *path, char **options)
++    int     OGR_Dr_DeleteDataSource (void *driver, char *)
++    void *  OGR_Dr_Open (void *driver, const char *path, int bupdate)
++    void *  OGR_F_Create (void *featuredefn)
++    void    OGR_F_Destroy (void *feature)
++    long    OGR_F_GetFID (void *feature)
++    int     OGR_F_IsFieldSet (void *feature, int n)
++    int     OGR_F_GetFieldAsDateTime (void *feature, int n, int *y, int *m, int *d, int *h, int *m, int *s, int *z)
++    double  OGR_F_GetFieldAsDouble (void *feature, int n)
++    int     OGR_F_GetFieldAsInteger (void *feature, int n)
++    char *  OGR_F_GetFieldAsString (void *feature, int n)
++    int     OGR_F_GetFieldCount (void *feature)
++    void *  OGR_F_GetFieldDefnRef (void *feature, int n)
++    int     OGR_F_GetFieldIndex (void *feature, char *name)
++    void *  OGR_F_GetGeometryRef (void *feature)
++    void    OGR_F_SetFieldDateTime (void *feature, int n, int y, int m, int d, int hh, int mm, int ss, int tz)
++    void    OGR_F_SetFieldDouble (void *feature, int n, double value)
++    void    OGR_F_SetFieldInteger (void *feature, int n, int value)
++    void    OGR_F_SetFieldString (void *feature, int n, char *value)
++    int     OGR_F_SetGeometryDirectly (void *feature, void *geometry)
++    void *  OGR_FD_Create (char *name)
++    int     OGR_FD_GetFieldCount (void *featuredefn)
++    void *  OGR_FD_GetFieldDefn (void *featuredefn, int n)
++    int     OGR_FD_GetGeomType (void *featuredefn)
++    char *  OGR_FD_GetName (void *featuredefn)
++    void *  OGR_Fld_Create (char *name, int fieldtype)
++    void    OGR_Fld_Destroy (void *fielddefn)
++    char *  OGR_Fld_GetNameRef (void *fielddefn)
++    int     OGR_Fld_GetPrecision (void *fielddefn)
++    int     OGR_Fld_GetType (void *fielddefn)
++    int     OGR_Fld_GetWidth (void *fielddefn)
++    void    OGR_Fld_Set (void *fielddefn, char *name, int fieldtype, int width, int precision, int justification)
++    void    OGR_Fld_SetPrecision (void *fielddefn, int n)
++    void    OGR_Fld_SetWidth (void *fielddefn, int n)
++    OGRErr  OGR_G_AddGeometryDirectly (void *geometry, void *part)
++    void    OGR_G_AddPoint (void *geometry, double x, double y, double z)
++    void    OGR_G_AddPoint_2D (void *geometry, double x, double y)
++    void    OGR_G_CloseRings (void *geometry)
++    void *  OGR_G_CreateGeometry (int wkbtypecode)
++    void    OGR_G_DestroyGeometry (void *geometry)
++    unsigned char *  OGR_G_ExportToJson (void *geometry)
++    void    OGR_G_ExportToWkb (void *geometry, int endianness, char *buffer)
++    int     OGR_G_GetCoordinateDimension (void *geometry)
++    int     OGR_G_GetGeometryCount (void *geometry)
++    unsigned char *  OGR_G_GetGeometryName (void *geometry)
++    int     OGR_G_GetGeometryType (void *geometry)
++    void *  OGR_G_GetGeometryRef (void *geometry, int n)
++    int     OGR_G_GetPointCount (void *geometry)
++    double  OGR_G_GetX (void *geometry, int n)
++    double  OGR_G_GetY (void *geometry, int n)
++    double  OGR_G_GetZ (void *geometry, int n)
++    void    OGR_G_ImportFromWkb (void *geometry, unsigned char *bytes, int nbytes)
++    int     OGR_G_WkbSize (void *geometry)
++    OGRErr  OGR_L_CreateFeature (void *layer, void *feature)
++    int     OGR_L_CreateField (void *layer, void *fielddefn, int flexible)
++    OGRErr  OGR_L_GetExtent (void *layer, void *extent, int force)
++    void *  OGR_L_GetFeature (void *layer, int n)
++    int     OGR_L_GetFeatureCount (void *layer, int m)
++    void *  OGR_L_GetLayerDefn (void *layer)
++    char *  OGR_L_GetName (void *layer)
++    void *  OGR_L_GetNextFeature (void *layer)
++    void *  OGR_L_GetSpatialFilter (void *layer)
++    void *  OGR_L_GetSpatialRef (void *layer)
++    void    OGR_L_ResetReading (void *layer)
++    void    OGR_L_SetSpatialFilter (void *layer, void *geometry)
++    void    OGR_L_SetSpatialFilterRect (
++                void *layer, double minx, double miny, double maxx, double maxy
++                )
++    int     OGR_L_TestCapability (void *layer, char *name)
++    void *  OGRGetDriverByName (char *)
++    void *  OGROpen (char *path, int mode, void *x)
++    void *  OGROpenShared (char *path, int mode, void *x)
++    int     OGRReleaseDataSource (void *datasource)
++    OGRErr  OGR_L_SetNextByIndex (void *layer, long nIndex)
++    long long OGR_F_GetFieldAsInteger64 (void *feature, int n)
++    void    OGR_F_SetFieldInteger64 (void *feature, int n, long long value)
+--- a/fiona/ogrext.pyx
++++ /dev/null
+@@ -1,1233 +0,0 @@
+-# These are extension functions and classes using the OGR C API.
+-
+-import datetime
+-import json
+-import locale
+-import logging
+-import os
+-import sys
+-import warnings
+-import math
+-import uuid
+-
+-from six import integer_types, string_types, text_type
+-
+-from fiona cimport ograpi
+-from fiona._geometry cimport GeomBuilder, OGRGeomBuilder
+-from fiona._err import cpl_errs
+-from fiona._geometry import GEOMETRY_TYPES
+-from fiona.errors import DriverError, SchemaError, CRSError, FionaValueError
+-from fiona.odict import OrderedDict
+-from fiona.rfc3339 import parse_date, parse_datetime, parse_time
+-from fiona.rfc3339 import FionaDateType, FionaDateTimeType, FionaTimeType
+-
+-
+-log = logging.getLogger("Fiona")
+-class NullHandler(logging.Handler):
+-    def emit(self, record):
+-        pass
+-log.addHandler(NullHandler())
+-
+-
+-# Mapping of OGR integer field types to Fiona field type names.
+-#
+-# Lists are currently unsupported in this version, but might be done as
+-# arrays in a future version.
+-
+-FIELD_TYPES = [
+-    'int',          # OFTInteger, Simple 32bit integer
+-    None,           # OFTIntegerList, List of 32bit integers
+-    'float',        # OFTReal, Double Precision floating point
+-    None,           # OFTRealList, List of doubles
+-    'str',          # OFTString, String of ASCII chars
+-    None,           # OFTStringList, Array of strings
+-    None,           # OFTWideString, deprecated
+-    None,           # OFTWideStringList, deprecated
+-    None,           # OFTBinary, Raw Binary data
+-    'date',         # OFTDate, Date
+-    'time',         # OFTTime, Time
+-    'datetime',     # OFTDateTime, Date and Time
+-    ]
+-
+-# Mapping of Fiona field type names to Python types.
+-FIELD_TYPES_MAP = {
+-    'int':      int,
+-    'float':    float,
+-    'str':      text_type,
+-    'date':     FionaDateType,
+-    'time':     FionaTimeType,
+-    'datetime': FionaDateTimeType
+-   }
+-
+-# OGR Layer capability
+-OLC_RANDOMREAD = b"RandomRead"
+-OLC_SEQUENTIALWRITE = b"SequentialWrite"
+-OLC_RANDOMWRITE = b"RandomWrite"
+-OLC_FASTSPATIALFILTER = b"FastSpatialFilter"
+-OLC_FASTFEATURECOUNT = b"FastFeatureCount"
+-OLC_FASTGETEXTENT = b"FastGetExtent"
+-OLC_FASTSETNEXTBYINDEX = b"FastSetNextByIndex"
+-OLC_CREATEFIELD = b"CreateField"
+-OLC_CREATEGEOMFIELD = b"CreateGeomField"
+-OLC_DELETEFIELD = b"DeleteField"
+-OLC_REORDERFIELDS = b"ReorderFields"
+-OLC_ALTERFIELDDEFN = b"AlterFieldDefn"
+-OLC_DELETEFEATURE = b"DeleteFeature"
+-OLC_STRINGSASUTF8 = b"StringsAsUTF8"
+-OLC_TRANSACTIONS = b"Transactions"
+-
+-# OGR integer error types.
+-
+-OGRERR_NONE = 0
+-OGRERR_NOT_ENOUGH_DATA = 1    # not enough data to deserialize */
+-OGRERR_NOT_ENOUGH_MEMORY = 2
+-OGRERR_UNSUPPORTED_GEOMETRY_TYPE = 3
+-OGRERR_UNSUPPORTED_OPERATION = 4
+-OGRERR_CORRUPT_DATA = 5
+-OGRERR_FAILURE = 6
+-OGRERR_UNSUPPORTED_SRS = 7
+-OGRERR_INVALID_HANDLE = 8
+-
+-# Recent versions of OGR can sometimes detect file encoding, but don't
+-# provide access yet to the detected encoding. Hence this variable.
+-OGR_DETECTED_ENCODING = '-ogr-detected-encoding'
+-
+-
+-def _explode(coords):
+-    """Explode a GeoJSON geometry's coordinates object and yield
+-    coordinate tuples. As long as the input is conforming, the type of
+-    the geometry doesn't matter."""
+-    for e in coords:
+-        if isinstance(e, (float, int)):
+-            yield coords
+-            break
+-        else:
+-            for f in _explode(e):
+-                yield f
+-
+-
+-def _bounds(geometry):
+-    """Bounding box of a GeoJSON geometry"""
+-    try:
+-        xyz = tuple(zip(*list(_explode(geometry['coordinates']))))
+-        return min(xyz[0]), min(xyz[1]), max(xyz[0]), max(xyz[1])
+-    except (KeyError, TypeError):
+-        return None
+-
+-def calc_gdal_version_num(maj, min, rev):
+-    """Calculates the internal gdal version number based on major, minor and revision"""
+-    return int(maj * 1000000 + min * 10000 + rev*100)
+-
+-def get_gdal_version_num():
+-    """Return current internal version number of gdal"""
+-    return int(ograpi.GDALVersionInfo("VERSION_NUM"))
+-
+-def get_gdal_release_name():
+-    """Return release name of gdal"""
+-    return ograpi.GDALVersionInfo("RELEASE_NAME")
+-
+-
+-# Feature extension classes and functions follow.
+-
+-cdef class FeatureBuilder:
+-    """Build Fiona features from OGR feature pointers.
+-
+-    No OGR objects are allocated by this function and the feature
+-    argument is not destroyed.
+-    """
+-
+-    cdef build(self, void *feature, encoding='utf-8', bbox=False, driver=None):
+-        # The only method anyone ever needs to call
+-        cdef void *fdefn
+-        cdef int i
+-        cdef int y = 0
+-        cdef int m = 0
+-        cdef int d = 0
+-        cdef int hh = 0
+-        cdef int mm = 0
+-        cdef int ss = 0
+-        cdef int tz = 0
+-        cdef int retval
+-        cdef char *key_c
+-        props = OrderedDict()
+-        for i in range(ograpi.OGR_F_GetFieldCount(feature)):
+-            fdefn = ograpi.OGR_F_GetFieldDefnRef(feature, i)
+-            if fdefn == NULL:
+-                raise ValueError("Null feature definition")
+-            key_c = ograpi.OGR_Fld_GetNameRef(fdefn)
+-            if key_c == NULL:
+-                raise ValueError("Null field name reference")
+-            key_b = key_c
+-            key = key_b.decode(encoding)
+-            fieldtypename = FIELD_TYPES[ograpi.OGR_Fld_GetType(fdefn)]
+-            if not fieldtypename:
+-                log.warn(
+-                    "Skipping field %s: invalid type %s", 
+-                    key,
+-                    ograpi.OGR_Fld_GetType(fdefn))
+-                continue
+-
+-            # TODO: other types
+-            fieldtype = FIELD_TYPES_MAP[fieldtypename]
+-            if not ograpi.OGR_F_IsFieldSet(feature, i):
+-                props[key] = None
+-            elif fieldtype is int:
+-                props[key] = ograpi.OGR_F_GetFieldAsInteger(feature, i)
+-            elif fieldtype is float:
+-                props[key] = ograpi.OGR_F_GetFieldAsDouble(feature, i)
+-
+-            elif fieldtype is text_type:
+-                try:
+-                    val = ograpi.OGR_F_GetFieldAsString(feature, i)
+-                    val = val.decode(encoding)
+-                except UnicodeDecodeError:
+-                    log.warn(
+-                        "Failed to decode %s using %s codec", val, encoding)
+-
+-                # Does the text contain a JSON object? Let's check.
+-                # Let's check as cheaply as we can.
+-                if driver == 'GeoJSON' and val.startswith('{'):
+-                    try:
+-                        val = json.loads(val)
+-                    except ValueError as err:
+-                        log.warn(str(err))
+-
+-                # Now add to the properties object.
+-                props[key] = val
+-
+-            elif fieldtype in (FionaDateType, FionaTimeType, FionaDateTimeType):
+-                retval = ograpi.OGR_F_GetFieldAsDateTime(
+-                    feature, i, &y, &m, &d, &hh, &mm, &ss, &tz)
+-                if fieldtype is FionaDateType:
+-                    props[key] = datetime.date(y, m, d).isoformat()
+-                elif fieldtype is FionaTimeType:
+-                    props[key] = datetime.time(hh, mm, ss).isoformat()
+-                else:
+-                    props[key] = datetime.datetime(
+-                        y, m, d, hh, mm, ss).isoformat()
+-            else:
+-                log.debug("%s: None, fieldtype: %r, %r" % (key, fieldtype, fieldtype in string_types))
+-                props[key] = None
+-
+-        cdef void *cogr_geometry = ograpi.OGR_F_GetGeometryRef(feature)
+-        if cogr_geometry is not NULL:
+-            geom = GeomBuilder().build(cogr_geometry)
+-        else:
+-            geom = None
+-        return {
+-            'type': 'Feature',
+-            'id': str(ograpi.OGR_F_GetFID(feature)),
+-            'geometry': geom,
+-            'properties': props }
+-
+-
+-cdef class OGRFeatureBuilder:
+-    
+-    """Builds an OGR Feature from a Fiona feature mapping.
+-
+-    Allocates one OGR Feature which should be destroyed by the caller.
+-    Borrows a layer definition from the collection.
+-    """
+-    
+-    cdef void * build(self, feature, collection) except NULL:
+-        cdef void *cogr_geometry = NULL
+-        cdef char *string_c
+-        cdef WritingSession session
+-        session = collection.session
+-        cdef void *cogr_layer = session.cogr_layer
+-        if cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-        cdef void *cogr_featuredefn = ograpi.OGR_L_GetLayerDefn(cogr_layer)
+-        if cogr_featuredefn == NULL:
+-            raise ValueError("Null feature definition")
+-        cdef void *cogr_feature = ograpi.OGR_F_Create(cogr_featuredefn)
+-        if cogr_feature == NULL:
+-            raise ValueError("Null feature")
+-        
+-        if feature['geometry'] is not None:
+-            cogr_geometry = OGRGeomBuilder().build(
+-                                feature['geometry'])
+-        ograpi.OGR_F_SetGeometryDirectly(cogr_feature, cogr_geometry)
+-        
+-        # OGR_F_SetFieldString takes UTF-8 encoded strings ('bytes' in 
+-        # Python 3).
+-        encoding = session.get_internalencoding()
+-
+-        for key, value in feature['properties'].items():
+-            log.debug(
+-                "Looking up %s in %s", key, repr(session._schema_mapping))
+-            ogr_key = session._schema_mapping[key]
+-            schema_type = collection.schema['properties'][key]
+-            try:
+-                key_bytes = ogr_key.encode(encoding)
+-            except UnicodeDecodeError:
+-                log.warn("Failed to encode %s using %s codec", key, encoding)
+-                key_bytes = ogr_key
+-            key_c = key_bytes
+-            i = ograpi.OGR_F_GetFieldIndex(cogr_feature, key_c)
+-            if i < 0:
+-                continue
+-
+-            # Special case: serialize dicts to assist OGR.
+-            if isinstance(value, dict):
+-                value = json.dumps(value)
+-
+-            # Continue over the standard OGR types.
+-            if isinstance(value, integer_types):
+-                ograpi.OGR_F_SetFieldInteger(cogr_feature, i, value)
+-            elif isinstance(value, float):
+-                ograpi.OGR_F_SetFieldDouble(cogr_feature, i, value)
+-            elif (isinstance(value, string_types) 
+-            and schema_type in ['date', 'time', 'datetime']):
+-                if schema_type == 'date':
+-                    y, m, d, hh, mm, ss, ff = parse_date(value)
+-                elif schema_type == 'time':
+-                    y, m, d, hh, mm, ss, ff = parse_time(value)
+-                else:
+-                    y, m, d, hh, mm, ss, ff = parse_datetime(value)
+-                ograpi.OGR_F_SetFieldDateTime(
+-                    cogr_feature, i, y, m, d, hh, mm, ss, 0)
+-            elif (isinstance(value, datetime.date)
+-            and schema_type == 'date'):
+-                y, m, d = value.year, value.month, value.day
+-                ograpi.OGR_F_SetFieldDateTime(
+-                    cogr_feature, i, y, m, d, 0, 0, 0, 0)
+-            elif (isinstance(value, datetime.datetime)
+-            and schema_type == 'datetime'):
+-                y, m, d = value.year, value.month, value.day
+-                hh, mm, ss = value.hour, value.minute, value.second
+-                ograpi.OGR_F_SetFieldDateTime(
+-                    cogr_feature, i, y, m, d, hh, mm, ss, 0)
+-            elif (isinstance(value, datetime.time)
+-            and schema_type == 'time'):
+-                hh, mm, ss = value.hour, value.minute, value.second
+-                ograpi.OGR_F_SetFieldDateTime(
+-                    cogr_feature, i, 0, 0, 0, hh, mm, ss, 0)
+-            elif isinstance(value, string_types):
+-                try:
+-                    value_bytes = value.encode(encoding)
+-                except UnicodeDecodeError:
+-                    log.warn(
+-                        "Failed to encode %s using %s codec", value, encoding)
+-                    value_bytes = value
+-                string_c = value_bytes
+-                ograpi.OGR_F_SetFieldString(cogr_feature, i, string_c)
+-            elif value is None:
+-                pass # keep field unset/null
+-            else:
+-                raise ValueError("Invalid field type %s" % type(value))
+-            log.debug("Set field %s: %s" % (key, value))
+-        return cogr_feature
+-
+-
+-cdef _deleteOgrFeature(void *cogr_feature):
+-    """Delete an OGR feature"""
+-    if cogr_feature is not NULL:
+-        ograpi.OGR_F_Destroy(cogr_feature)
+-    cogr_feature = NULL
+-
+-
+-def featureRT(feature, collection):
+-    # For testing purposes only, leaks the JSON data
+-    cdef void *cogr_feature = OGRFeatureBuilder().build(feature, collection)
+-    cdef void *cogr_geometry = ograpi.OGR_F_GetGeometryRef(cogr_feature)
+-    if cogr_geometry == NULL:
+-        raise ValueError("Null geometry")
+-    log.debug("Geometry: %s" % ograpi.OGR_G_ExportToJson(cogr_geometry))
+-    encoding = collection.encoding or 'utf-8'
+-    result = FeatureBuilder().build(
+-        cogr_feature,
+-        bbox=False,
+-        encoding=encoding,
+-        driver=collection.driver
+-    )
+-    _deleteOgrFeature(cogr_feature)
+-    return result
+-
+-
+-# Collection-related extension classes and functions
+-
+-cdef class Session:
+-    
+-    cdef void *cogr_ds
+-    cdef void *cogr_layer
+-    cdef object _fileencoding
+-    cdef object _encoding
+-    cdef object collection
+-
+-    def __cinit__(self):
+-        self.cogr_ds = NULL
+-        self.cogr_layer = NULL
+-        self._fileencoding = None
+-        self._encoding = None
+-
+-    def __dealloc__(self):
+-        self.stop()
+-
+-    def start(self, collection):
+-        cdef const char *path_c = NULL
+-        cdef const char *name_c = NULL
+-        cdef void *drv = NULL
+-        cdef void *ds = NULL
+-
+-        if collection.path == '-':
+-            path = '/vsistdin/'
+-        else:
+-            path = collection.path
+-        try:
+-            path_b = path.encode('utf-8')
+-        except UnicodeDecodeError:
+-            # Presume already a UTF-8 encoded string
+-            path_b = path
+-        path_c = path_b
+-        
+-        with cpl_errs:
+-            drivers = []
+-            if collection._driver:
+-                drivers = [collection._driver]
+-            elif collection.enabled_drivers:
+-                drivers = collection.enabled_drivers
+-            if drivers:
+-                for name in drivers:
+-                    name_b = name.encode()
+-                    name_c = name_b
+-                    log.debug("Trying driver: %s", name)
+-                    drv = ograpi.OGRGetDriverByName(name_c)
+-                    if drv != NULL:
+-                        ds = ograpi.OGR_Dr_Open(drv, path_c, 0)
+-                    if ds != NULL:
+-                        self.cogr_ds = ds
+-                        collection._driver = name
+-                        break
+-            else:
+-                self.cogr_ds = ograpi.OGROpen(path_c, 0, NULL)
+-
+-        if self.cogr_ds == NULL:
+-            raise FionaValueError(
+-                "No dataset found at path '%s' using drivers: %s" % (
+-                    collection.path,
+-                    drivers or '*'))
+-        
+-        if isinstance(collection.name, string_types):
+-            name_b = collection.name.encode('utf-8')
+-            name_c = name_b
+-            self.cogr_layer = ograpi.OGR_DS_GetLayerByName(
+-                                self.cogr_ds, name_c)
+-        elif isinstance(collection.name, int):
+-            self.cogr_layer = ograpi.OGR_DS_GetLayer(
+-                                self.cogr_ds, collection.name)
+-            name_c = ograpi.OGR_L_GetName(self.cogr_layer)
+-            name_b = name_c
+-            collection.name = name_b.decode('utf-8')
+-
+-        if self.cogr_layer == NULL:
+-            raise ValueError("Null layer: " + repr(collection.name))
+-        
+-        self.collection = collection
+-        
+-        userencoding = self.collection.encoding
+-        if userencoding:
+-            ograpi.CPLSetThreadLocalConfigOption('SHAPE_ENCODING', '')
+-            self._fileencoding = userencoding.upper()
+-        else:
+-            self._fileencoding = (
+-                ograpi.OGR_L_TestCapability(
+-                    self.cogr_layer, OLC_STRINGSASUTF8) and
+-                OGR_DETECTED_ENCODING) or (
+-                self.get_driver() == "ESRI Shapefile" and
+-                'ISO-8859-1') or locale.getpreferredencoding().upper()
+-
+-    def stop(self):
+-        self.cogr_layer = NULL
+-        if self.cogr_ds is not NULL:
+-            ograpi.OGR_DS_Destroy(self.cogr_ds)
+-        self.cogr_ds = NULL
+-
+-    def get_fileencoding(self):
+-        return self._fileencoding
+-
+-    def get_internalencoding(self):
+-        if not self._encoding:
+-            fileencoding = self.get_fileencoding()
+-            self._encoding = (
+-                ograpi.OGR_L_TestCapability(
+-                    self.cogr_layer, OLC_STRINGSASUTF8) and
+-                'utf-8') or fileencoding
+-        return self._encoding
+-
+-    def get_length(self):
+-        if self.cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-        return ograpi.OGR_L_GetFeatureCount(self.cogr_layer, 0)
+-
+-    def get_driver(self):
+-        cdef void *cogr_driver = ograpi.OGR_DS_GetDriver(self.cogr_ds)
+-        if cogr_driver == NULL:
+-            raise ValueError("Null driver")
+-        cdef char *name = ograpi.OGR_Dr_GetName(cogr_driver)
+-        driver_name = name
+-        return driver_name.decode()
+- 
+-    def get_schema(self):
+-        cdef int i
+-        cdef int n
+-        cdef void *cogr_featuredefn
+-        cdef void *cogr_fielddefn
+-        cdef char *key_c
+-        props = []
+-        
+-        if self.cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-
+-        cogr_featuredefn = ograpi.OGR_L_GetLayerDefn(self.cogr_layer)
+-        if cogr_featuredefn == NULL:
+-            raise ValueError("Null feature definition")
+-        n = ograpi.OGR_FD_GetFieldCount(cogr_featuredefn)
+-        for i from 0 <= i < n:
+-            cogr_fielddefn = ograpi.OGR_FD_GetFieldDefn(cogr_featuredefn, i)
+-            if cogr_fielddefn == NULL:
+-                raise ValueError("Null field definition")
+-            key_c = ograpi.OGR_Fld_GetNameRef(cogr_fielddefn)
+-            key_b = key_c
+-            if not bool(key_b):
+-                raise ValueError("Invalid field name ref: %s" % key)
+-            key = key_b.decode(self.get_internalencoding())
+-            fieldtypename = FIELD_TYPES[ograpi.OGR_Fld_GetType(cogr_fielddefn)]
+-            if not fieldtypename:
+-                log.warn(
+-                    "Skipping field %s: invalid type %s", 
+-                    key,
+-                    ograpi.OGR_Fld_GetType(cogr_fielddefn))
+-                continue
+-            val = fieldtypename
+-            if fieldtypename == 'float':
+-                fmt = ""
+-                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
+-                if width: # and width != 24:
+-                    fmt = ":%d" % width
+-                precision = ograpi.OGR_Fld_GetPrecision(cogr_fielddefn)
+-                if precision: # and precision != 15:
+-                    fmt += ".%d" % precision
+-                val = "float" + fmt
+-            elif fieldtypename == 'int':
+-                fmt = ""
+-                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
+-                if width: # and width != 11:
+-                    fmt = ":%d" % width
+-                val = fieldtypename + fmt
+-            elif fieldtypename == 'str':
+-                fmt = ""
+-                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
+-                if width: # and width != 80:
+-                    fmt = ":%d" % width
+-                val = fieldtypename + fmt
+-
+-            props.append((key, val))
+-
+-        cdef unsigned int geom_type = ograpi.OGR_FD_GetGeomType(
+-            cogr_featuredefn)
+-        return {
+-            'properties': OrderedDict(props), 
+-            'geometry': GEOMETRY_TYPES[geom_type]}
+-
+-    def get_crs(self):
+-        cdef char *proj_c = NULL
+-        cdef char *auth_key = NULL
+-        cdef char *auth_val = NULL
+-        cdef void *cogr_crs = NULL
+-        if self.cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-        cogr_crs = ograpi.OGR_L_GetSpatialRef(self.cogr_layer)
+-        crs = {}
+-        if cogr_crs is not NULL:
+-            log.debug("Got coordinate system")
+-
+-            retval = ograpi.OSRAutoIdentifyEPSG(cogr_crs)
+-            if retval > 0:
+-                log.info("Failed to auto identify EPSG: %d", retval)
+-            
+-            auth_key = ograpi.OSRGetAuthorityName(cogr_crs, NULL)
+-            auth_val = ograpi.OSRGetAuthorityCode(cogr_crs, NULL)
+-
+-            if auth_key != NULL and auth_val != NULL:
+-                key_b = auth_key
+-                key = key_b.decode('utf-8')
+-                if key == 'EPSG':
+-                    val_b = auth_val
+-                    val = val_b.decode('utf-8')
+-                    crs['init'] = "epsg:" + val
+-            else:
+-                ograpi.OSRExportToProj4(cogr_crs, &proj_c)
+-                if proj_c == NULL:
+-                    raise ValueError("Null projection")
+-                proj_b = proj_c
+-                log.debug("Params: %s", proj_b)
+-                value = proj_b.decode()
+-                value = value.strip()
+-                for param in value.split():
+-                    kv = param.split("=")
+-                    if len(kv) == 2:
+-                        k, v = kv
+-                        try:
+-                            v = float(v)
+-                            if v % 1 == 0:
+-                                v = int(v)
+-                        except ValueError:
+-                            # Leave v as a string
+-                            pass
+-                    elif len(kv) == 1:
+-                        k, v = kv[0], True
+-                    else:
+-                        raise ValueError("Unexpected proj parameter %s" % param)
+-                    k = k.lstrip("+")
+-                    crs[k] = v
+-
+-            ograpi.CPLFree(proj_c)
+-        else:
+-            log.debug("Projection not found (cogr_crs was NULL)")
+-        return crs
+-
+-    def get_crs_wkt(self):
+-        cdef char *proj_c = NULL
+-        if self.cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-        cogr_crs = ograpi.OGR_L_GetSpatialRef(self.cogr_layer)
+-        crs_wkt = ""
+-        if cogr_crs is not NULL:
+-            log.debug("Got coordinate system")
+-            ograpi.OSRExportToWkt(cogr_crs, &proj_c)
+-            if proj_c == NULL:
+-                raise ValueError("Null projection")
+-            proj_b = proj_c
+-            crs_wkt = proj_b.decode('utf-8')
+-            ograpi.CPLFree(proj_c)
+-        else:
+-            log.debug("Projection not found (cogr_crs was NULL)")
+-        return crs_wkt
+-
+-    def get_extent(self):
+-        if self.cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-        cdef ograpi.OGREnvelope extent
+-        result = ograpi.OGR_L_GetExtent(self.cogr_layer, &extent, 1)
+-        return (extent.MinX, extent.MinY, extent.MaxX, extent.MaxY)
+-
+-    def has_feature(self, fid):
+-        """Provides access to feature data by FID.
+-
+-        Supports Collection.__contains__().
+-        """
+-        cdef void * cogr_feature
+-        fid = int(fid)
+-        cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, fid)
+-        if cogr_feature != NULL:
+-            _deleteOgrFeature(cogr_feature)
+-            return True
+-        else:
+-            return False
+-
+-    def get_feature(self, fid):
+-        """Provides access to feature data by FID.
+-
+-        Supports Collection.__contains__().
+-        """
+-        cdef void * cogr_feature
+-        fid = int(fid)
+-        cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, fid)
+-        if cogr_feature != NULL:
+-            _deleteOgrFeature(cogr_feature)
+-            return True
+-        else:
+-            return False
+-
+-
+-    def __getitem__(self, item):
+-        cdef void * cogr_feature
+-        if isinstance(item, slice):
+-            itr = Iterator(self.collection, item.start, item.stop, item.step)
+-            log.debug("Slice: %r", item)
+-            return list(itr)
+-        elif isinstance(item, int):
+-            index = item
+-            # from the back
+-            if index < 0:
+-                ftcount = ograpi.OGR_L_GetFeatureCount(self.cogr_layer, 0)
+-                if ftcount == -1:
+-                    raise IndexError(
+-                        "collection's dataset does not support negative indexes")
+-                index += ftcount
+-            cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, index)
+-            if cogr_feature == NULL:
+-                return None
+-            feature = FeatureBuilder().build(
+-                cogr_feature,
+-                bbox=False,
+-                encoding=self.get_internalencoding(),
+-                driver=self.collection.driver
+-            )
+-            _deleteOgrFeature(cogr_feature)
+-            return feature
+-
+-
+-    def isactive(self):
+-        if self.cogr_layer != NULL and self.cogr_ds != NULL:
+-            return 1
+-        else:
+-            return 0
+-
+-
+-cdef class WritingSession(Session):
+-    
+-    cdef object _schema_mapping
+-
+-    def start(self, collection):
+-        cdef void *cogr_fielddefn
+-        cdef void *cogr_driver
+-        cdef void *cogr_ds
+-        cdef void *cogr_layer
+-        cdef void *cogr_srs = NULL
+-        cdef char **options = NULL
+-        self.collection = collection
+-        cdef char *path_c
+-        cdef char *driver_c
+-        cdef char *name_c
+-        cdef char *proj_c
+-        cdef char *fileencoding_c
+-        path = collection.path
+-
+-        if collection.mode == 'a':
+-            if os.path.exists(path):
+-                try:
+-                    path_b = path.encode('utf-8')
+-                except UnicodeDecodeError:
+-                    path_b = path
+-                path_c = path_b
+-                with cpl_errs:
+-                    self.cogr_ds = ograpi.OGROpen(path_c, 1, NULL)
+-                if self.cogr_ds == NULL:
+-                    raise RuntimeError("Failed to open %s" % path)
+-                cogr_driver = ograpi.OGR_DS_GetDriver(self.cogr_ds)
+-                if cogr_driver == NULL:
+-                    raise ValueError("Null driver")
+-
+-                if isinstance(collection.name, string_types):
+-                    name_b = collection.name.encode()
+-                    name_c = name_b
+-                    self.cogr_layer = ograpi.OGR_DS_GetLayerByName(
+-                                        self.cogr_ds, name_c)
+-                elif isinstance(collection.name, int):
+-                    self.cogr_layer = ograpi.OGR_DS_GetLayer(
+-                                        self.cogr_ds, collection.name)
+-
+-                if self.cogr_layer == NULL:
+-                    raise RuntimeError(
+-                        "Failed to get layer %s" % collection.name)
+-            else:
+-                raise OSError("No such file or directory %s" % path)
+-
+-            userencoding = self.collection.encoding
+-            self._fileencoding = (userencoding or (
+-                ograpi.OGR_L_TestCapability(self.cogr_layer, OLC_STRINGSASUTF8) and
+-                OGR_DETECTED_ENCODING) or (
+-                self.get_driver() == "ESRI Shapefile" and
+-                'ISO-8859-1') or locale.getpreferredencoding()).upper()
+-
+-        elif collection.mode == 'w':
+-            try:
+-                path_b = path.encode('utf-8')
+-            except UnicodeDecodeError:
+-                path_b = path
+-            path_c = path_b
+-            driver_b = collection.driver.encode()
+-            driver_c = driver_b
+-
+-            cogr_driver = ograpi.OGRGetDriverByName(driver_c)
+-            if cogr_driver == NULL:
+-                raise ValueError("Null driver")
+-
+-            if not os.path.exists(path):
+-                cogr_ds = ograpi.OGR_Dr_CreateDataSource(
+-                    cogr_driver, path_c, NULL)
+-
+-            else:
+-                with cpl_errs:
+-                    cogr_ds = ograpi.OGROpen(path_c, 1, NULL)
+-                if cogr_ds == NULL:
+-                    cogr_ds = ograpi.OGR_Dr_CreateDataSource(
+-                        cogr_driver, path_c, NULL)
+-
+-                elif collection.name is None:
+-                    ograpi.OGR_DS_Destroy(cogr_ds)
+-                    cogr_ds == NULL
+-                    log.debug("Deleted pre-existing data at %s", path)
+-                    
+-                    cogr_ds = ograpi.OGR_Dr_CreateDataSource(
+-                        cogr_driver, path_c, NULL)
+-
+-                else:
+-                    pass
+-
+-            if cogr_ds == NULL:
+-                raise RuntimeError("Failed to open %s" % path)
+-            else:
+-                self.cogr_ds = cogr_ds
+-
+-            # Set the spatial reference system from the crs given to the
+-            # collection constructor. We by-pass the crs_wkt and crs
+-            # properties because they aren't accessible until the layer
+-            # is constructed (later).
+-            col_crs = collection._crs_wkt or collection._crs
+-            if col_crs:
+-                cogr_srs = ograpi.OSRNewSpatialReference(NULL)
+-                if cogr_srs == NULL:
+-                    raise ValueError("NULL spatial reference")
+-                # First, check for CRS strings like "EPSG:3857".
+-                if isinstance(col_crs, string_types):
+-                    proj_b = col_crs.encode('utf-8')
+-                    proj_c = proj_b
+-                    ograpi.OSRSetFromUserInput(cogr_srs, proj_c)
+-                elif isinstance(col_crs, dict):
+-                    # EPSG is a special case.
+-                    init = col_crs.get('init')
+-                    if init:
+-                        log.debug("Init: %s", init)
+-                        auth, val = init.split(':')
+-                        if auth.upper() == 'EPSG':
+-                            log.debug("Setting EPSG: %s", val)
+-                            ograpi.OSRImportFromEPSG(cogr_srs, int(val))
+-                    else:
+-                        params = []
+-                        col_crs['wktext'] = True
+-                        for k, v in col_crs.items():
+-                            if v is True or (k in ('no_defs', 'wktext') and v):
+-                                params.append("+%s" % k)
+-                            else:
+-                                params.append("+%s=%s" % (k, v))
+-                        proj = " ".join(params)
+-                        log.debug("PROJ.4 to be imported: %r", proj)
+-                        proj_b = proj.encode('utf-8')
+-                        proj_c = proj_b
+-                        ograpi.OSRImportFromProj4(cogr_srs, proj_c)
+-                else:
+-                    raise ValueError("Invalid CRS")
+-
+-                # Fixup, export to WKT, and set the GDAL dataset's projection.
+-                ograpi.OSRFixup(cogr_srs)
+-
+-            # Figure out what encoding to use. The encoding parameter given
+-            # to the collection constructor takes highest precedence, then
+-            # 'iso-8859-1', then the system's default encoding as last resort.
+-            sysencoding = locale.getpreferredencoding()
+-            userencoding = collection.encoding
+-            self._fileencoding = (userencoding or (
+-                collection.driver == "ESRI Shapefile" and
+-                'ISO-8859-1') or sysencoding).upper()
+-
+-            fileencoding = self.get_fileencoding()
+-            if fileencoding:
+-                fileencoding_b = fileencoding.encode()
+-                fileencoding_c = fileencoding_b
+-                options = ograpi.CSLSetNameValue(options, "ENCODING", fileencoding_c)
+-
+-            # Does the layer exist already? If so, we delete it.
+-            layer_count = ograpi.OGR_DS_GetLayerCount(self.cogr_ds)
+-            layer_names = []
+-            for i in range(layer_count):
+-                cogr_layer = ograpi.OGR_DS_GetLayer(cogr_ds, i)
+-                name_c = ograpi.OGR_L_GetName(cogr_layer)
+-                name_b = name_c
+-                layer_names.append(name_b.decode('utf-8'))
+-
+-            idx = -1
+-            if isinstance(collection.name, string_types):
+-                if collection.name in layer_names:
+-                    idx = layer_names.index(collection.name)
+-            elif isinstance(collection.name, int):
+-                if collection.name >= 0 and collection.name < layer_count:
+-                    idx = collection.name
+-            if idx >= 0:
+-                log.debug("Deleted pre-existing layer at %s", collection.name)
+-                ograpi.OGR_DS_DeleteLayer(self.cogr_ds, idx)
+-            
+-            # Create the named layer in the datasource.
+-            name_b = collection.name.encode('utf-8')
+-            name_c = name_b
+-            self.cogr_layer = ograpi.OGR_DS_CreateLayer(
+-                self.cogr_ds, 
+-                name_c,
+-                cogr_srs,
+-                <unsigned int>[k for k,v in GEOMETRY_TYPES.items() if 
+-                    v == collection.schema.get('geometry', 'Unknown')][0],
+-                options
+-                )
+-
+-            if cogr_srs != NULL:
+-                ograpi.OSRDestroySpatialReference(cogr_srs)
+-            if options != NULL:
+-                ograpi.CSLDestroy(options)
+-
+-            if self.cogr_layer == NULL:
+-                raise ValueError("Null layer")
+-            log.debug("Created layer")
+-            
+-            # Next, make a layer definition from the given schema properties,
+-            # which are an ordered dict since Fiona 1.0.1.
+-            for key, value in collection.schema['properties'].items():
+-                log.debug("Creating field: %s %s", key, value)
+-
+-                # Convert 'long' to 'int'. See
+-                # https://github.com/Toblerity/Fiona/issues/101.
+-                if value == 'long':
+-                    value = 'int'
+-                
+-                # Is there a field width/precision?
+-                width = precision = None
+-                if ':' in value:
+-                    value, fmt = value.split(':')
+-                    if '.' in fmt:
+-                        width, precision = map(int, fmt.split('.'))
+-                    else:
+-                        width = int(fmt)
+-                
+-                encoding = self.get_internalencoding()
+-                key_bytes = key.encode(encoding)
+-                cogr_fielddefn = ograpi.OGR_Fld_Create(
+-                    key_bytes, 
+-                    FIELD_TYPES.index(value) )
+-                if cogr_fielddefn == NULL:
+-                    raise ValueError("Null field definition")
+-                if width:
+-                    ograpi.OGR_Fld_SetWidth(cogr_fielddefn, width)
+-                if precision:
+-                    ograpi.OGR_Fld_SetPrecision(cogr_fielddefn, precision)
+-                ograpi.OGR_L_CreateField(self.cogr_layer, cogr_fielddefn, 1)
+-                ograpi.OGR_Fld_Destroy(cogr_fielddefn)
+-            log.debug("Created fields")
+-
+-        # Mapping of the Python collection schema to the munged 
+-        # OGR schema.
+-        ogr_schema = self.get_schema()
+-        self._schema_mapping = dict(zip(
+-            collection.schema['properties'].keys(), 
+-            ogr_schema['properties'].keys() ))
+-
+-        log.debug("Writing started")
+-
+-    def writerecs(self, records, collection):
+-        """Writes buffered records to OGR."""
+-        cdef void *cogr_driver
+-        cdef void *cogr_feature
+-
+-        cdef void *cogr_layer = self.cogr_layer
+-        if cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-    
+-        schema_geom_type = collection.schema['geometry']
+-        cogr_driver = ograpi.OGR_DS_GetDriver(self.cogr_ds)
+-        if ograpi.OGR_Dr_GetName(cogr_driver) == b"GeoJSON":
+-            def validate_geometry_type(rec):
+-                return True
+-        elif ograpi.OGR_Dr_GetName(cogr_driver) == b"ESRI Shapefile" \
+-                and "Point" not in collection.schema['geometry']:
+-            schema_geom_type = collection.schema['geometry'].lstrip(
+-                "3D ").lstrip("Multi")
+-            def validate_geometry_type(rec):
+-                return rec['geometry'] is None or \
+-                rec['geometry']['type'].lstrip(
+-                    "3D ").lstrip("Multi") == schema_geom_type
+-        else:
+-            schema_geom_type = collection.schema['geometry'].lstrip("3D ")
+-            def validate_geometry_type(rec):
+-                return rec['geometry'] is None or \
+-                       rec['geometry']['type'].lstrip("3D ") == schema_geom_type
+-
+-        schema_props_keys = set(collection.schema['properties'].keys())
+-        for record in records:
+-            log.debug("Creating feature in layer: %s" % record)
+-            # Validate against collection's schema.
+-            if set(record['properties'].keys()) != schema_props_keys:
+-                raise ValueError(
+-                    "Record does not match collection schema: %r != %r" % (
+-                        record['properties'].keys(), 
+-                        list(schema_props_keys) ))
+-            if not validate_geometry_type(record):
+-                raise ValueError(
+-                    "Record's geometry type does not match "
+-                    "collection schema's geometry type: %r != %r" % (
+-                         record['geometry']['type'],
+-                         collection.schema['geometry'] ))
+-
+-            cogr_feature = OGRFeatureBuilder().build(record, collection)
+-            result = ograpi.OGR_L_CreateFeature(cogr_layer, cogr_feature)
+-            if result != OGRERR_NONE:
+-                raise RuntimeError("Failed to write record: %s" % record)
+-            _deleteOgrFeature(cogr_feature)
+-
+-    def sync(self, collection):
+-        """Syncs OGR to disk."""
+-        cdef void *cogr_ds = self.cogr_ds
+-        cdef void *cogr_layer = self.cogr_layer
+-        if cogr_ds == NULL:
+-            raise ValueError("Null data source")
+-        log.debug("Syncing OGR to disk")
+-        retval = ograpi.OGR_DS_SyncToDisk(cogr_ds)
+-        if retval != OGRERR_NONE:
+-            raise RuntimeError("Failed to sync to disk")
+-
+-
+-cdef class Iterator:
+-
+-    """Provides iterated access to feature data.
+-    """
+-
+-    # Reference to its Collection
+-    cdef collection
+-    cdef encoding
+-    cdef int next_index
+-    cdef stop
+-    cdef start
+-    cdef step
+-    cdef fastindex
+-    cdef stepsign
+-
+-    def __init__(self, collection, 
+-            start=None, stop=None, step=None, bbox=None, mask=None):
+-        if collection.session is None:
+-            raise ValueError("I/O operation on closed collection")
+-        self.collection = collection
+-        cdef Session session
+-        cdef void *cogr_geometry
+-        session = self.collection.session
+-        cdef void *cogr_layer = session.cogr_layer
+-        if cogr_layer == NULL:
+-            raise ValueError("Null layer")
+-        ograpi.OGR_L_ResetReading(cogr_layer)
+-        
+-        if bbox and mask:
+-            raise ValueError("mask and bbox can not be set together")
+-        
+-        if bbox:
+-            ograpi.OGR_L_SetSpatialFilterRect(
+-                cogr_layer, bbox[0], bbox[1], bbox[2], bbox[3])
+-        elif mask:
+-            cogr_geometry = OGRGeomBuilder().build(mask)
+-            ograpi.OGR_L_SetSpatialFilter(cogr_layer, cogr_geometry)
+-            ograpi.OGR_G_DestroyGeometry(cogr_geometry)
+-            
+-        else:
+-            ograpi.OGR_L_SetSpatialFilter(
+-                cogr_layer, NULL)
+-        self.encoding = session.get_internalencoding()
+-
+-        self.fastindex = ograpi.OGR_L_TestCapability(
+-            session.cogr_layer, OLC_FASTSETNEXTBYINDEX)
+-
+-        ftcount = ograpi.OGR_L_GetFeatureCount(session.cogr_layer, 0)
+-        if ftcount == -1 and ((start is not None and start < 0) or
+-                              (stop is not None and stop < 0)):
+-            raise IndexError(
+-                "collection's dataset does not support negative slice indexes")
+-
+-        if stop is not None and stop < 0:
+-            stop += ftcount
+-
+-        if start is None:
+-            start = 0
+-        if start is not None and start < 0:
+-            start += ftcount
+-
+-        # step size
+-        if step is None:
+-            step = 1
+-        if step == 0:
+-            raise ValueError("slice step cannot be zero")
+-        if step < 0 and not self.fastindex:
+-            warnings.warn("Layer does not support" \
+-                    "OLCFastSetNextByIndex, negative step size may" \
+-                    " be slow", RuntimeWarning)
+-        self.stepsign = int(math.copysign(1, step))
+-        self.stop = stop
+-        self.start = start
+-        self.step = step
+-
+-        self.next_index = start
+-        log.debug("Index: %d", self.next_index)
+-        ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
+-
+-
+-    def __iter__(self):
+-        return self
+-
+-
+-    def _next(self):
+-        """Internal method to set read cursor to next item"""
+-
+-        cdef Session session
+-        session = self.collection.session
+-
+-        # Check if next_index is valid
+-        if self.next_index < 0:
+-            raise StopIteration
+-        
+-        if self.stepsign == 1:
+-            if self.next_index < self.start or (self.stop is not None and self.next_index >= self.stop):
+-                raise StopIteration
+-        else:
+-            if self.next_index > self.start or (self.stop is not None and self.next_index <= self.stop):
+-                raise StopIteration
+-
+-
+-        # Set read cursor to next_item position
+-        if self.step > 1 and self.fastindex:
+-            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
+-
+-        elif self.step > 1 and not self.fastindex and not self.next_index == self.start:
+-            for _ in range(self.step - 1):
+-                # TODO rbuffat add test -> OGR_L_GetNextFeature increments cursor by 1, therefore self.step - 1 as one increment was performed when feature is read
+-                cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
+-                if cogr_feature == NULL:
+-                    raise StopIteration
+-        elif self.step > 1 and not self.fastindex and self.next_index == self.start:
+-            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
+-
+-        elif self.step == 0:
+-            # ograpi.OGR_L_GetNextFeature increments read cursor by one
+-            pass
+-        elif self.step < 0:
+-            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
+-            
+-        # set the next index
+-        self.next_index += self.step
+-
+-
+-    def __next__(self):
+-        cdef void * cogr_feature
+-        cdef Session session
+-        session = self.collection.session
+-
+-        #Update read cursor
+-        self._next()
+-
+-        # Get the next feature.
+-        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
+-        if cogr_feature == NULL:
+-            raise StopIteration
+-
+-        feature = FeatureBuilder().build(
+-            cogr_feature,
+-            bbox=False,
+-            encoding=self.encoding,
+-            driver=self.collection.driver
+-        )
+-        _deleteOgrFeature(cogr_feature)
+-        return feature
+-
+-
+-cdef class ItemsIterator(Iterator):
+-
+-    def __next__(self):
+-
+-        cdef long fid
+-        cdef void * cogr_feature
+-        cdef Session session
+-        session = self.collection.session
+-
+-        #Update read cursor
+-        self._next()
+-
+-        # Get the next feature.
+-        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
+-        if cogr_feature == NULL:
+-            raise StopIteration
+-
+-
+-        fid = ograpi.OGR_F_GetFID(cogr_feature)
+-        feature = FeatureBuilder().build(
+-            cogr_feature,
+-            bbox=False,
+-            encoding=self.encoding,
+-            driver=self.collection.driver
+-        )
+-        _deleteOgrFeature(cogr_feature)
+-
+-        return fid, feature
+-
+-
+-cdef class KeysIterator(Iterator):
+-
+-    def __next__(self):
+-        cdef long fid
+-        cdef void * cogr_feature
+-        cdef Session session
+-        session = self.collection.session
+-
+-        #Update read cursor
+-        self._next()
+-
+-        # Get the next feature.
+-        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
+-        if cogr_feature == NULL:
+-            raise StopIteration
+-
+-        fid = ograpi.OGR_F_GetFID(cogr_feature)
+-        _deleteOgrFeature(cogr_feature)
+-
+-        return fid
+-
+-
+-def _listlayers(path):
+-
+-    """Provides a list of the layers in an OGR data source.
+-    """
+-    
+-    cdef void *cogr_ds
+-    cdef void *cogr_layer
+-    cdef char *path_c
+-    cdef char *name_c
+-    
+-    # Open OGR data source.
+-    try:
+-        path_b = path.encode('utf-8')
+-    except UnicodeDecodeError:
+-        path_b = path
+-    path_c = path_b
+-    with cpl_errs:
+-        cogr_ds = ograpi.OGROpen(path_c, 0, NULL)
+-    if cogr_ds == NULL:
+-        raise ValueError("No data available at path '%s'" % path)
+-    
+-    # Loop over the layers to get their names.
+-    layer_count = ograpi.OGR_DS_GetLayerCount(cogr_ds)
+-    layer_names = []
+-    for i in range(layer_count):
+-        cogr_layer = ograpi.OGR_DS_GetLayer(cogr_ds, i)
+-        name_c = ograpi.OGR_L_GetName(cogr_layer)
+-        name_b = name_c
+-        layer_names.append(name_b.decode('utf-8'))
+-    
+-    # Close up data source.
+-    if cogr_ds is not NULL:
+-        ograpi.OGR_DS_Destroy(cogr_ds)
+-    cogr_ds = NULL
+-
+-    return layer_names
+-
+-def buffer_to_virtual_file(bytesbuf):
+-    """Maps a bytes buffer to a virtual file.
+-    """
+-    vsi_filename = os.path.join('/vsimem', uuid.uuid4().hex)
+-    vsi_cfilename = vsi_filename if not isinstance(vsi_filename, string_types) else vsi_filename.encode('utf-8')
+-
+-    vsi_handle = ograpi.VSIFileFromMemBuffer(vsi_cfilename, bytesbuf, len(bytesbuf), 0)
+-    if vsi_handle == NULL:
+-        raise OSError('failed to map buffer to file')
+-    if ograpi.VSIFCloseL(vsi_handle) != 0:
+-        raise OSError('failed to close mapped file handle')
+-
+-    return vsi_filename
+-
+-def remove_virtual_file(vsi_filename):
+-    vsi_cfilename = vsi_filename if not isinstance(vsi_filename, string_types) else vsi_filename.encode('utf-8')
+-    return ograpi.VSIUnlink(vsi_cfilename)
+-
+-
+--- /dev/null
++++ b/fiona/ogrext1.pyx
+@@ -0,0 +1,1229 @@
++# These are extension functions and classes using the OGR C API.
++
++import datetime
++import json
++import locale
++import logging
++import os
++import sys
++import warnings
++import math
++import uuid
++
++from six import integer_types, string_types, text_type
++
++from fiona cimport ograpi
++from fiona._geometry cimport GeomBuilder, OGRGeomBuilder
++from fiona._err import cpl_errs
++from fiona._geometry import GEOMETRY_TYPES
++from fiona.errors import DriverError, SchemaError, CRSError, FionaValueError
++from fiona.odict import OrderedDict
++from fiona.rfc3339 import parse_date, parse_datetime, parse_time
++from fiona.rfc3339 import FionaDateType, FionaDateTimeType, FionaTimeType
++
++
++log = logging.getLogger("Fiona")
++class NullHandler(logging.Handler):
++    def emit(self, record):
++        pass
++log.addHandler(NullHandler())
++
++
++# Mapping of OGR integer field types to Fiona field type names.
++#
++# Lists are currently unsupported in this version, but might be done as
++# arrays in a future version.
++
++FIELD_TYPES = [
++    'int',          # OFTInteger, Simple 32bit integer
++    None,           # OFTIntegerList, List of 32bit integers
++    'float',        # OFTReal, Double Precision floating point
++    None,           # OFTRealList, List of doubles
++    'str',          # OFTString, String of ASCII chars
++    None,           # OFTStringList, Array of strings
++    None,           # OFTWideString, deprecated
++    None,           # OFTWideStringList, deprecated
++    None,           # OFTBinary, Raw Binary data
++    'date',         # OFTDate, Date
++    'time',         # OFTTime, Time
++    'datetime',     # OFTDateTime, Date and Time
++    ]
++
++# Mapping of Fiona field type names to Python types.
++FIELD_TYPES_MAP = {
++    'int':      int,
++    'float':    float,
++    'str':      text_type,
++    'date':     FionaDateType,
++    'time':     FionaTimeType,
++    'datetime': FionaDateTimeType
++   }
++
++# OGR Layer capability
++OLC_RANDOMREAD = b"RandomRead"
++OLC_SEQUENTIALWRITE = b"SequentialWrite"
++OLC_RANDOMWRITE = b"RandomWrite"
++OLC_FASTSPATIALFILTER = b"FastSpatialFilter"
++OLC_FASTFEATURECOUNT = b"FastFeatureCount"
++OLC_FASTGETEXTENT = b"FastGetExtent"
++OLC_FASTSETNEXTBYINDEX = b"FastSetNextByIndex"
++OLC_CREATEFIELD = b"CreateField"
++OLC_CREATEGEOMFIELD = b"CreateGeomField"
++OLC_DELETEFIELD = b"DeleteField"
++OLC_REORDERFIELDS = b"ReorderFields"
++OLC_ALTERFIELDDEFN = b"AlterFieldDefn"
++OLC_DELETEFEATURE = b"DeleteFeature"
++OLC_STRINGSASUTF8 = b"StringsAsUTF8"
++OLC_TRANSACTIONS = b"Transactions"
++
++# OGR integer error types.
++
++OGRERR_NONE = 0
++OGRERR_NOT_ENOUGH_DATA = 1    # not enough data to deserialize */
++OGRERR_NOT_ENOUGH_MEMORY = 2
++OGRERR_UNSUPPORTED_GEOMETRY_TYPE = 3
++OGRERR_UNSUPPORTED_OPERATION = 4
++OGRERR_CORRUPT_DATA = 5
++OGRERR_FAILURE = 6
++OGRERR_UNSUPPORTED_SRS = 7
++OGRERR_INVALID_HANDLE = 8
++
++
++def _explode(coords):
++    """Explode a GeoJSON geometry's coordinates object and yield
++    coordinate tuples. As long as the input is conforming, the type of
++    the geometry doesn't matter."""
++    for e in coords:
++        if isinstance(e, (float, int)):
++            yield coords
++            break
++        else:
++            for f in _explode(e):
++                yield f
++
++
++def _bounds(geometry):
++    """Bounding box of a GeoJSON geometry"""
++    try:
++        xyz = tuple(zip(*list(_explode(geometry['coordinates']))))
++        return min(xyz[0]), min(xyz[1]), max(xyz[0]), max(xyz[1])
++    except (KeyError, TypeError):
++        return None
++
++def calc_gdal_version_num(maj, min, rev):
++    """Calculates the internal gdal version number based on major, minor and revision"""
++    return int(maj * 1000000 + min * 10000 + rev*100)
++
++def get_gdal_version_num():
++    """Return current internal version number of gdal"""
++    return int(ograpi.GDALVersionInfo("VERSION_NUM"))
++
++def get_gdal_release_name():
++    """Return release name of gdal"""
++    return ograpi.GDALVersionInfo("RELEASE_NAME")
++
++
++# Feature extension classes and functions follow.
++
++cdef class FeatureBuilder:
++    """Build Fiona features from OGR feature pointers.
++
++    No OGR objects are allocated by this function and the feature
++    argument is not destroyed.
++    """
++
++    cdef build(self, void *feature, encoding='utf-8', bbox=False, driver=None):
++        # The only method anyone ever needs to call
++        cdef void *fdefn
++        cdef int i
++        cdef int y = 0
++        cdef int m = 0
++        cdef int d = 0
++        cdef int hh = 0
++        cdef int mm = 0
++        cdef int ss = 0
++        cdef int tz = 0
++        cdef int retval
++        cdef char *key_c
++        props = OrderedDict()
++        for i in range(ograpi.OGR_F_GetFieldCount(feature)):
++            fdefn = ograpi.OGR_F_GetFieldDefnRef(feature, i)
++            if fdefn == NULL:
++                raise ValueError("Null feature definition")
++            key_c = ograpi.OGR_Fld_GetNameRef(fdefn)
++            if key_c == NULL:
++                raise ValueError("Null field name reference")
++            key_b = key_c
++            key = key_b.decode(encoding)
++            fieldtypename = FIELD_TYPES[ograpi.OGR_Fld_GetType(fdefn)]
++            if not fieldtypename:
++                log.warn(
++                    "Skipping field %s: invalid type %s", 
++                    key,
++                    ograpi.OGR_Fld_GetType(fdefn))
++                continue
++
++            # TODO: other types
++            fieldtype = FIELD_TYPES_MAP[fieldtypename]
++            if not ograpi.OGR_F_IsFieldSet(feature, i):
++                props[key] = None
++            elif fieldtype is int:
++                props[key] = ograpi.OGR_F_GetFieldAsInteger(feature, i)
++            elif fieldtype is float:
++                props[key] = ograpi.OGR_F_GetFieldAsDouble(feature, i)
++
++            elif fieldtype is text_type:
++                try:
++                    val = ograpi.OGR_F_GetFieldAsString(feature, i)
++                    val = val.decode(encoding)
++                except UnicodeDecodeError:
++                    log.warn(
++                        "Failed to decode %s using %s codec", val, encoding)
++
++                # Does the text contain a JSON object? Let's check.
++                # Let's check as cheaply as we can.
++                if driver == 'GeoJSON' and val.startswith('{'):
++                    try:
++                        val = json.loads(val)
++                    except ValueError as err:
++                        log.warn(str(err))
++
++                # Now add to the properties object.
++                props[key] = val
++
++            elif fieldtype in (FionaDateType, FionaTimeType, FionaDateTimeType):
++                retval = ograpi.OGR_F_GetFieldAsDateTime(
++                    feature, i, &y, &m, &d, &hh, &mm, &ss, &tz)
++                if fieldtype is FionaDateType:
++                    props[key] = datetime.date(y, m, d).isoformat()
++                elif fieldtype is FionaTimeType:
++                    props[key] = datetime.time(hh, mm, ss).isoformat()
++                else:
++                    props[key] = datetime.datetime(
++                        y, m, d, hh, mm, ss).isoformat()
++            else:
++                log.debug("%s: None, fieldtype: %r, %r" % (key, fieldtype, fieldtype in string_types))
++                props[key] = None
++
++        cdef void *cogr_geometry = ograpi.OGR_F_GetGeometryRef(feature)
++        if cogr_geometry is not NULL:
++            geom = GeomBuilder().build(cogr_geometry)
++        else:
++            geom = None
++        return {
++            'type': 'Feature',
++            'id': str(ograpi.OGR_F_GetFID(feature)),
++            'geometry': geom,
++            'properties': props }
++
++
++cdef class OGRFeatureBuilder:
++    
++    """Builds an OGR Feature from a Fiona feature mapping.
++
++    Allocates one OGR Feature which should be destroyed by the caller.
++    Borrows a layer definition from the collection.
++    """
++    
++    cdef void * build(self, feature, collection) except NULL:
++        cdef void *cogr_geometry = NULL
++        cdef char *string_c
++        cdef WritingSession session
++        session = collection.session
++        cdef void *cogr_layer = session.cogr_layer
++        if cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cdef void *cogr_featuredefn = ograpi.OGR_L_GetLayerDefn(cogr_layer)
++        if cogr_featuredefn == NULL:
++            raise ValueError("Null feature definition")
++        cdef void *cogr_feature = ograpi.OGR_F_Create(cogr_featuredefn)
++        if cogr_feature == NULL:
++            raise ValueError("Null feature")
++        
++        if feature['geometry'] is not None:
++            cogr_geometry = OGRGeomBuilder().build(
++                                feature['geometry'])
++        ograpi.OGR_F_SetGeometryDirectly(cogr_feature, cogr_geometry)
++        
++        # OGR_F_SetFieldString takes UTF-8 encoded strings ('bytes' in 
++        # Python 3).
++        encoding = session.get_internalencoding()
++
++        for key, value in feature['properties'].items():
++            log.debug(
++                "Looking up %s in %s", key, repr(session._schema_mapping))
++            ogr_key = session._schema_mapping[key]
++            schema_type = collection.schema['properties'][key]
++            try:
++                key_bytes = ogr_key.encode(encoding)
++            except UnicodeDecodeError:
++                log.warn("Failed to encode %s using %s codec", key, encoding)
++                key_bytes = ogr_key
++            key_c = key_bytes
++            i = ograpi.OGR_F_GetFieldIndex(cogr_feature, key_c)
++            if i < 0:
++                continue
++
++            # Special case: serialize dicts to assist OGR.
++            if isinstance(value, dict):
++                value = json.dumps(value)
++
++            # Continue over the standard OGR types.
++            if isinstance(value, integer_types):
++                ograpi.OGR_F_SetFieldInteger(cogr_feature, i, value)
++            elif isinstance(value, float):
++                ograpi.OGR_F_SetFieldDouble(cogr_feature, i, value)
++            elif (isinstance(value, string_types) 
++            and schema_type in ['date', 'time', 'datetime']):
++                if schema_type == 'date':
++                    y, m, d, hh, mm, ss, ff = parse_date(value)
++                elif schema_type == 'time':
++                    y, m, d, hh, mm, ss, ff = parse_time(value)
++                else:
++                    y, m, d, hh, mm, ss, ff = parse_datetime(value)
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, y, m, d, hh, mm, ss, 0)
++            elif (isinstance(value, datetime.date)
++            and schema_type == 'date'):
++                y, m, d = value.year, value.month, value.day
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, y, m, d, 0, 0, 0, 0)
++            elif (isinstance(value, datetime.datetime)
++            and schema_type == 'datetime'):
++                y, m, d = value.year, value.month, value.day
++                hh, mm, ss = value.hour, value.minute, value.second
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, y, m, d, hh, mm, ss, 0)
++            elif (isinstance(value, datetime.time)
++            and schema_type == 'time'):
++                hh, mm, ss = value.hour, value.minute, value.second
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, 0, 0, 0, hh, mm, ss, 0)
++            elif isinstance(value, string_types):
++                try:
++                    value_bytes = value.encode(encoding)
++                except UnicodeDecodeError:
++                    log.warn(
++                        "Failed to encode %s using %s codec", value, encoding)
++                    value_bytes = value
++                string_c = value_bytes
++                ograpi.OGR_F_SetFieldString(cogr_feature, i, string_c)
++            elif value is None:
++                pass # keep field unset/null
++            else:
++                raise ValueError("Invalid field type %s" % type(value))
++            log.debug("Set field %s: %s" % (key, value))
++        return cogr_feature
++
++
++cdef _deleteOgrFeature(void *cogr_feature):
++    """Delete an OGR feature"""
++    if cogr_feature is not NULL:
++        ograpi.OGR_F_Destroy(cogr_feature)
++    cogr_feature = NULL
++
++
++def featureRT(feature, collection):
++    # For testing purposes only, leaks the JSON data
++    cdef void *cogr_feature = OGRFeatureBuilder().build(feature, collection)
++    cdef void *cogr_geometry = ograpi.OGR_F_GetGeometryRef(cogr_feature)
++    if cogr_geometry == NULL:
++        raise ValueError("Null geometry")
++    log.debug("Geometry: %s" % ograpi.OGR_G_ExportToJson(cogr_geometry))
++    encoding = collection.encoding or 'utf-8'
++    result = FeatureBuilder().build(
++        cogr_feature,
++        bbox=False,
++        encoding=encoding,
++        driver=collection.driver
++    )
++    _deleteOgrFeature(cogr_feature)
++    return result
++
++
++# Collection-related extension classes and functions
++
++cdef class Session:
++    
++    cdef void *cogr_ds
++    cdef void *cogr_layer
++    cdef object _fileencoding
++    cdef object _encoding
++    cdef object collection
++
++    def __cinit__(self):
++        self.cogr_ds = NULL
++        self.cogr_layer = NULL
++        self._fileencoding = None
++        self._encoding = None
++
++    def __dealloc__(self):
++        self.stop()
++
++    def start(self, collection):
++        cdef const char *path_c = NULL
++        cdef const char *name_c = NULL
++        cdef void *drv = NULL
++        cdef void *ds = NULL
++
++        if collection.path == '-':
++            path = '/vsistdin/'
++        else:
++            path = collection.path
++        try:
++            path_b = path.encode('utf-8')
++        except UnicodeDecodeError:
++            # Presume already a UTF-8 encoded string
++            path_b = path
++        path_c = path_b
++        
++        with cpl_errs:
++            drivers = []
++            if collection._driver:
++                drivers = [collection._driver]
++            elif collection.enabled_drivers:
++                drivers = collection.enabled_drivers
++            if drivers:
++                for name in drivers:
++                    name_b = name.encode()
++                    name_c = name_b
++                    log.debug("Trying driver: %s", name)
++                    drv = ograpi.OGRGetDriverByName(name_c)
++                    if drv != NULL:
++                        ds = ograpi.OGR_Dr_Open(drv, path_c, 0)
++                    if ds != NULL:
++                        self.cogr_ds = ds
++                        collection._driver = name
++                        break
++            else:
++                self.cogr_ds = ograpi.OGROpen(path_c, 0, NULL)
++
++        if self.cogr_ds == NULL:
++            raise FionaValueError(
++                "No dataset found at path '%s' using drivers: %s" % (
++                    collection.path,
++                    drivers or '*'))
++        
++        if isinstance(collection.name, string_types):
++            name_b = collection.name.encode('utf-8')
++            name_c = name_b
++            self.cogr_layer = ograpi.OGR_DS_GetLayerByName(
++                                self.cogr_ds, name_c)
++        elif isinstance(collection.name, int):
++            self.cogr_layer = ograpi.OGR_DS_GetLayer(
++                                self.cogr_ds, collection.name)
++            name_c = ograpi.OGR_L_GetName(self.cogr_layer)
++            name_b = name_c
++            collection.name = name_b.decode('utf-8')
++
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer: " + repr(collection.name))
++        
++        self.collection = collection
++        
++        userencoding = self.collection.encoding
++        if userencoding:
++            ograpi.CPLSetThreadLocalConfigOption('SHAPE_ENCODING', '')
++            self._fileencoding = userencoding.upper()
++        else:
++            self._fileencoding = (
++                ograpi.OGR_L_TestCapability(
++                    self.cogr_layer, OLC_STRINGSASUTF8) and
++                'utf-8') or (
++                self.get_driver() == "ESRI Shapefile" and
++                'ISO-8859-1') or locale.getpreferredencoding().upper()
++
++    def stop(self):
++        self.cogr_layer = NULL
++        if self.cogr_ds is not NULL:
++            ograpi.OGR_DS_Destroy(self.cogr_ds)
++        self.cogr_ds = NULL
++
++    def get_fileencoding(self):
++        return self._fileencoding
++
++    def get_internalencoding(self):
++        if not self._encoding:
++            fileencoding = self.get_fileencoding()
++            self._encoding = (
++                ograpi.OGR_L_TestCapability(
++                    self.cogr_layer, OLC_STRINGSASUTF8) and
++                'utf-8') or fileencoding
++        return self._encoding
++
++    def get_length(self):
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        return ograpi.OGR_L_GetFeatureCount(self.cogr_layer, 0)
++
++    def get_driver(self):
++        cdef void *cogr_driver = ograpi.OGR_DS_GetDriver(self.cogr_ds)
++        if cogr_driver == NULL:
++            raise ValueError("Null driver")
++        cdef char *name = ograpi.OGR_Dr_GetName(cogr_driver)
++        driver_name = name
++        return driver_name.decode()
++ 
++    def get_schema(self):
++        cdef int i
++        cdef int n
++        cdef void *cogr_featuredefn
++        cdef void *cogr_fielddefn
++        cdef char *key_c
++        props = []
++        
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++
++        cogr_featuredefn = ograpi.OGR_L_GetLayerDefn(self.cogr_layer)
++        if cogr_featuredefn == NULL:
++            raise ValueError("Null feature definition")
++        n = ograpi.OGR_FD_GetFieldCount(cogr_featuredefn)
++        for i from 0 <= i < n:
++            cogr_fielddefn = ograpi.OGR_FD_GetFieldDefn(cogr_featuredefn, i)
++            if cogr_fielddefn == NULL:
++                raise ValueError("Null field definition")
++            key_c = ograpi.OGR_Fld_GetNameRef(cogr_fielddefn)
++            key_b = key_c
++            if not bool(key_b):
++                raise ValueError("Invalid field name ref: %s" % key)
++            key = key_b.decode(self.get_internalencoding())
++            fieldtypename = FIELD_TYPES[ograpi.OGR_Fld_GetType(cogr_fielddefn)]
++            if not fieldtypename:
++                log.warn(
++                    "Skipping field %s: invalid type %s", 
++                    key,
++                    ograpi.OGR_Fld_GetType(cogr_fielddefn))
++                continue
++            val = fieldtypename
++            if fieldtypename == 'float':
++                fmt = ""
++                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
++                if width: # and width != 24:
++                    fmt = ":%d" % width
++                precision = ograpi.OGR_Fld_GetPrecision(cogr_fielddefn)
++                if precision: # and precision != 15:
++                    fmt += ".%d" % precision
++                val = "float" + fmt
++            elif fieldtypename == 'int':
++                fmt = ""
++                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
++                if width: # and width != 11:
++                    fmt = ":%d" % width
++                val = fieldtypename + fmt
++            elif fieldtypename == 'str':
++                fmt = ""
++                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
++                if width: # and width != 80:
++                    fmt = ":%d" % width
++                val = fieldtypename + fmt
++
++            props.append((key, val))
++
++        cdef unsigned int geom_type = ograpi.OGR_FD_GetGeomType(
++            cogr_featuredefn)
++        return {
++            'properties': OrderedDict(props), 
++            'geometry': GEOMETRY_TYPES[geom_type]}
++
++    def get_crs(self):
++        cdef char *proj_c = NULL
++        cdef char *auth_key = NULL
++        cdef char *auth_val = NULL
++        cdef void *cogr_crs = NULL
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cogr_crs = ograpi.OGR_L_GetSpatialRef(self.cogr_layer)
++        crs = {}
++        if cogr_crs is not NULL:
++            log.debug("Got coordinate system")
++
++            retval = ograpi.OSRAutoIdentifyEPSG(cogr_crs)
++            if retval > 0:
++                log.info("Failed to auto identify EPSG: %d", retval)
++            
++            auth_key = ograpi.OSRGetAuthorityName(cogr_crs, NULL)
++            auth_val = ograpi.OSRGetAuthorityCode(cogr_crs, NULL)
++
++            if auth_key != NULL and auth_val != NULL:
++                key_b = auth_key
++                key = key_b.decode('utf-8')
++                if key == 'EPSG':
++                    val_b = auth_val
++                    val = val_b.decode('utf-8')
++                    crs['init'] = "epsg:" + val
++            else:
++                ograpi.OSRExportToProj4(cogr_crs, &proj_c)
++                if proj_c == NULL:
++                    raise ValueError("Null projection")
++                proj_b = proj_c
++                log.debug("Params: %s", proj_b)
++                value = proj_b.decode()
++                value = value.strip()
++                for param in value.split():
++                    kv = param.split("=")
++                    if len(kv) == 2:
++                        k, v = kv
++                        try:
++                            v = float(v)
++                            if v % 1 == 0:
++                                v = int(v)
++                        except ValueError:
++                            # Leave v as a string
++                            pass
++                    elif len(kv) == 1:
++                        k, v = kv[0], True
++                    else:
++                        raise ValueError("Unexpected proj parameter %s" % param)
++                    k = k.lstrip("+")
++                    crs[k] = v
++
++            ograpi.CPLFree(proj_c)
++        else:
++            log.debug("Projection not found (cogr_crs was NULL)")
++        return crs
++
++    def get_crs_wkt(self):
++        cdef char *proj_c = NULL
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cogr_crs = ograpi.OGR_L_GetSpatialRef(self.cogr_layer)
++        crs_wkt = ""
++        if cogr_crs is not NULL:
++            log.debug("Got coordinate system")
++            ograpi.OSRExportToWkt(cogr_crs, &proj_c)
++            if proj_c == NULL:
++                raise ValueError("Null projection")
++            proj_b = proj_c
++            crs_wkt = proj_b.decode('utf-8')
++            ograpi.CPLFree(proj_c)
++        else:
++            log.debug("Projection not found (cogr_crs was NULL)")
++        return crs_wkt
++
++    def get_extent(self):
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cdef ograpi.OGREnvelope extent
++        result = ograpi.OGR_L_GetExtent(self.cogr_layer, &extent, 1)
++        return (extent.MinX, extent.MinY, extent.MaxX, extent.MaxY)
++
++    def has_feature(self, fid):
++        """Provides access to feature data by FID.
++
++        Supports Collection.__contains__().
++        """
++        cdef void * cogr_feature
++        fid = int(fid)
++        cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, fid)
++        if cogr_feature != NULL:
++            _deleteOgrFeature(cogr_feature)
++            return True
++        else:
++            return False
++
++    def get_feature(self, fid):
++        """Provides access to feature data by FID.
++
++        Supports Collection.__contains__().
++        """
++        cdef void * cogr_feature
++        fid = int(fid)
++        cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, fid)
++        if cogr_feature != NULL:
++            _deleteOgrFeature(cogr_feature)
++            return True
++        else:
++            return False
++
++
++    def __getitem__(self, item):
++        cdef void * cogr_feature
++        if isinstance(item, slice):
++            itr = Iterator(self.collection, item.start, item.stop, item.step)
++            log.debug("Slice: %r", item)
++            return list(itr)
++        elif isinstance(item, int):
++            index = item
++            # from the back
++            if index < 0:
++                ftcount = ograpi.OGR_L_GetFeatureCount(self.cogr_layer, 0)
++                if ftcount == -1:
++                    raise IndexError(
++                        "collection's dataset does not support negative indexes")
++                index += ftcount
++            cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, index)
++            if cogr_feature == NULL:
++                return None
++            feature = FeatureBuilder().build(
++                cogr_feature,
++                bbox=False,
++                encoding=self.get_internalencoding(),
++                driver=self.collection.driver
++            )
++            _deleteOgrFeature(cogr_feature)
++            return feature
++
++
++    def isactive(self):
++        if self.cogr_layer != NULL and self.cogr_ds != NULL:
++            return 1
++        else:
++            return 0
++
++
++cdef class WritingSession(Session):
++    
++    cdef object _schema_mapping
++
++    def start(self, collection):
++        cdef void *cogr_fielddefn
++        cdef void *cogr_driver
++        cdef void *cogr_ds
++        cdef void *cogr_layer
++        cdef void *cogr_srs = NULL
++        cdef char **options = NULL
++        self.collection = collection
++        cdef char *path_c
++        cdef char *driver_c
++        cdef char *name_c
++        cdef char *proj_c
++        cdef char *fileencoding_c
++        path = collection.path
++
++        if collection.mode == 'a':
++            if os.path.exists(path):
++                try:
++                    path_b = path.encode('utf-8')
++                except UnicodeDecodeError:
++                    path_b = path
++                path_c = path_b
++                with cpl_errs:
++                    self.cogr_ds = ograpi.OGROpen(path_c, 1, NULL)
++                if self.cogr_ds == NULL:
++                    raise RuntimeError("Failed to open %s" % path)
++                cogr_driver = ograpi.OGR_DS_GetDriver(self.cogr_ds)
++                if cogr_driver == NULL:
++                    raise ValueError("Null driver")
++
++                if isinstance(collection.name, string_types):
++                    name_b = collection.name.encode()
++                    name_c = name_b
++                    self.cogr_layer = ograpi.OGR_DS_GetLayerByName(
++                                        self.cogr_ds, name_c)
++                elif isinstance(collection.name, int):
++                    self.cogr_layer = ograpi.OGR_DS_GetLayer(
++                                        self.cogr_ds, collection.name)
++
++                if self.cogr_layer == NULL:
++                    raise RuntimeError(
++                        "Failed to get layer %s" % collection.name)
++            else:
++                raise OSError("No such file or directory %s" % path)
++
++            userencoding = self.collection.encoding
++            self._fileencoding = (userencoding or (
++                ograpi.OGR_L_TestCapability(self.cogr_layer, OLC_STRINGSASUTF8) and
++                'utf-8') or (
++                self.get_driver() == "ESRI Shapefile" and
++                'ISO-8859-1') or locale.getpreferredencoding()).upper()
++
++        elif collection.mode == 'w':
++            try:
++                path_b = path.encode('utf-8')
++            except UnicodeDecodeError:
++                path_b = path
++            path_c = path_b
++            driver_b = collection.driver.encode()
++            driver_c = driver_b
++
++            cogr_driver = ograpi.OGRGetDriverByName(driver_c)
++            if cogr_driver == NULL:
++                raise ValueError("Null driver")
++
++            if not os.path.exists(path):
++                cogr_ds = ograpi.OGR_Dr_CreateDataSource(
++                    cogr_driver, path_c, NULL)
++
++            else:
++                with cpl_errs:
++                    cogr_ds = ograpi.OGROpen(path_c, 1, NULL)
++                if cogr_ds == NULL:
++                    cogr_ds = ograpi.OGR_Dr_CreateDataSource(
++                        cogr_driver, path_c, NULL)
++
++                elif collection.name is None:
++                    ograpi.OGR_DS_Destroy(cogr_ds)
++                    cogr_ds == NULL
++                    log.debug("Deleted pre-existing data at %s", path)
++                    
++                    cogr_ds = ograpi.OGR_Dr_CreateDataSource(
++                        cogr_driver, path_c, NULL)
++
++                else:
++                    pass
++
++            if cogr_ds == NULL:
++                raise RuntimeError("Failed to open %s" % path)
++            else:
++                self.cogr_ds = cogr_ds
++
++            # Set the spatial reference system from the crs given to the
++            # collection constructor. We by-pass the crs_wkt and crs
++            # properties because they aren't accessible until the layer
++            # is constructed (later).
++            col_crs = collection._crs_wkt or collection._crs
++            if col_crs:
++                cogr_srs = ograpi.OSRNewSpatialReference(NULL)
++                if cogr_srs == NULL:
++                    raise ValueError("NULL spatial reference")
++                # First, check for CRS strings like "EPSG:3857".
++                if isinstance(col_crs, string_types):
++                    proj_b = col_crs.encode('utf-8')
++                    proj_c = proj_b
++                    ograpi.OSRSetFromUserInput(cogr_srs, proj_c)
++                elif isinstance(col_crs, dict):
++                    # EPSG is a special case.
++                    init = col_crs.get('init')
++                    if init:
++                        log.debug("Init: %s", init)
++                        auth, val = init.split(':')
++                        if auth.upper() == 'EPSG':
++                            log.debug("Setting EPSG: %s", val)
++                            ograpi.OSRImportFromEPSG(cogr_srs, int(val))
++                    else:
++                        params = []
++                        col_crs['wktext'] = True
++                        for k, v in col_crs.items():
++                            if v is True or (k in ('no_defs', 'wktext') and v):
++                                params.append("+%s" % k)
++                            else:
++                                params.append("+%s=%s" % (k, v))
++                        proj = " ".join(params)
++                        log.debug("PROJ.4 to be imported: %r", proj)
++                        proj_b = proj.encode('utf-8')
++                        proj_c = proj_b
++                        ograpi.OSRImportFromProj4(cogr_srs, proj_c)
++                else:
++                    raise ValueError("Invalid CRS")
++
++                # Fixup, export to WKT, and set the GDAL dataset's projection.
++                ograpi.OSRFixup(cogr_srs)
++
++            # Figure out what encoding to use. The encoding parameter given
++            # to the collection constructor takes highest precedence, then
++            # 'iso-8859-1', then the system's default encoding as last resort.
++            sysencoding = locale.getpreferredencoding()
++            userencoding = collection.encoding
++            self._fileencoding = (userencoding or (
++                collection.driver == "ESRI Shapefile" and
++                'ISO-8859-1') or sysencoding).upper()
++
++            fileencoding = self.get_fileencoding()
++            if fileencoding:
++                fileencoding_b = fileencoding.encode()
++                fileencoding_c = fileencoding_b
++                options = ograpi.CSLSetNameValue(options, "ENCODING", fileencoding_c)
++
++            # Does the layer exist already? If so, we delete it.
++            layer_count = ograpi.OGR_DS_GetLayerCount(self.cogr_ds)
++            layer_names = []
++            for i in range(layer_count):
++                cogr_layer = ograpi.OGR_DS_GetLayer(cogr_ds, i)
++                name_c = ograpi.OGR_L_GetName(cogr_layer)
++                name_b = name_c
++                layer_names.append(name_b.decode('utf-8'))
++
++            idx = -1
++            if isinstance(collection.name, string_types):
++                if collection.name in layer_names:
++                    idx = layer_names.index(collection.name)
++            elif isinstance(collection.name, int):
++                if collection.name >= 0 and collection.name < layer_count:
++                    idx = collection.name
++            if idx >= 0:
++                log.debug("Deleted pre-existing layer at %s", collection.name)
++                ograpi.OGR_DS_DeleteLayer(self.cogr_ds, idx)
++            
++            # Create the named layer in the datasource.
++            name_b = collection.name.encode('utf-8')
++            name_c = name_b
++            self.cogr_layer = ograpi.OGR_DS_CreateLayer(
++                self.cogr_ds, 
++                name_c,
++                cogr_srs,
++                <unsigned int>[k for k,v in GEOMETRY_TYPES.items() if 
++                    v == collection.schema.get('geometry', 'Unknown')][0],
++                options
++                )
++
++            if cogr_srs != NULL:
++                ograpi.OSRDestroySpatialReference(cogr_srs)
++            if options != NULL:
++                ograpi.CSLDestroy(options)
++
++            if self.cogr_layer == NULL:
++                raise ValueError("Null layer")
++            log.debug("Created layer")
++            
++            # Next, make a layer definition from the given schema properties,
++            # which are an ordered dict since Fiona 1.0.1.
++            for key, value in collection.schema['properties'].items():
++                log.debug("Creating field: %s %s", key, value)
++
++                # Convert 'long' to 'int'. See
++                # https://github.com/Toblerity/Fiona/issues/101.
++                if value == 'long':
++                    value = 'int'
++                
++                # Is there a field width/precision?
++                width = precision = None
++                if ':' in value:
++                    value, fmt = value.split(':')
++                    if '.' in fmt:
++                        width, precision = map(int, fmt.split('.'))
++                    else:
++                        width = int(fmt)
++                
++                encoding = self.get_internalencoding()
++                key_bytes = key.encode(encoding)
++                cogr_fielddefn = ograpi.OGR_Fld_Create(
++                    key_bytes, 
++                    FIELD_TYPES.index(value) )
++                if cogr_fielddefn == NULL:
++                    raise ValueError("Null field definition")
++                if width:
++                    ograpi.OGR_Fld_SetWidth(cogr_fielddefn, width)
++                if precision:
++                    ograpi.OGR_Fld_SetPrecision(cogr_fielddefn, precision)
++                ograpi.OGR_L_CreateField(self.cogr_layer, cogr_fielddefn, 1)
++                ograpi.OGR_Fld_Destroy(cogr_fielddefn)
++            log.debug("Created fields")
++
++        # Mapping of the Python collection schema to the munged 
++        # OGR schema.
++        ogr_schema = self.get_schema()
++        self._schema_mapping = dict(zip(
++            collection.schema['properties'].keys(), 
++            ogr_schema['properties'].keys() ))
++
++        log.debug("Writing started")
++
++    def writerecs(self, records, collection):
++        """Writes buffered records to OGR."""
++        cdef void *cogr_driver
++        cdef void *cogr_feature
++
++        cdef void *cogr_layer = self.cogr_layer
++        if cogr_layer == NULL:
++            raise ValueError("Null layer")
++    
++        schema_geom_type = collection.schema['geometry']
++        cogr_driver = ograpi.OGR_DS_GetDriver(self.cogr_ds)
++        if ograpi.OGR_Dr_GetName(cogr_driver) == b"GeoJSON":
++            def validate_geometry_type(rec):
++                return True
++        elif ograpi.OGR_Dr_GetName(cogr_driver) == b"ESRI Shapefile" \
++                and "Point" not in collection.schema['geometry']:
++            schema_geom_type = collection.schema['geometry'].lstrip(
++                "3D ").lstrip("Multi")
++            def validate_geometry_type(rec):
++                return rec['geometry'] is None or \
++                rec['geometry']['type'].lstrip(
++                    "3D ").lstrip("Multi") == schema_geom_type
++        else:
++            schema_geom_type = collection.schema['geometry'].lstrip("3D ")
++            def validate_geometry_type(rec):
++                return rec['geometry'] is None or \
++                       rec['geometry']['type'].lstrip("3D ") == schema_geom_type
++
++        schema_props_keys = set(collection.schema['properties'].keys())
++        for record in records:
++            log.debug("Creating feature in layer: %s" % record)
++            # Validate against collection's schema.
++            if set(record['properties'].keys()) != schema_props_keys:
++                raise ValueError(
++                    "Record does not match collection schema: %r != %r" % (
++                        record['properties'].keys(), 
++                        list(schema_props_keys) ))
++            if not validate_geometry_type(record):
++                raise ValueError(
++                    "Record's geometry type does not match "
++                    "collection schema's geometry type: %r != %r" % (
++                         record['geometry']['type'],
++                         collection.schema['geometry'] ))
++
++            cogr_feature = OGRFeatureBuilder().build(record, collection)
++            result = ograpi.OGR_L_CreateFeature(cogr_layer, cogr_feature)
++            if result != OGRERR_NONE:
++                raise RuntimeError("Failed to write record: %s" % record)
++            _deleteOgrFeature(cogr_feature)
++
++    def sync(self, collection):
++        """Syncs OGR to disk."""
++        cdef void *cogr_ds = self.cogr_ds
++        cdef void *cogr_layer = self.cogr_layer
++        if cogr_ds == NULL:
++            raise ValueError("Null data source")
++        log.debug("Syncing OGR to disk")
++        retval = ograpi.OGR_DS_SyncToDisk(cogr_ds)
++        if retval != OGRERR_NONE:
++            raise RuntimeError("Failed to sync to disk")
++
++
++cdef class Iterator:
++
++    """Provides iterated access to feature data.
++    """
++
++    # Reference to its Collection
++    cdef collection
++    cdef encoding
++    cdef int next_index
++    cdef stop
++    cdef start
++    cdef step
++    cdef fastindex
++    cdef stepsign
++
++    def __init__(self, collection, 
++            start=None, stop=None, step=None, bbox=None, mask=None):
++        if collection.session is None:
++            raise ValueError("I/O operation on closed collection")
++        self.collection = collection
++        cdef Session session
++        cdef void *cogr_geometry
++        session = self.collection.session
++        cdef void *cogr_layer = session.cogr_layer
++        if cogr_layer == NULL:
++            raise ValueError("Null layer")
++        ograpi.OGR_L_ResetReading(cogr_layer)
++        
++        if bbox and mask:
++            raise ValueError("mask and bbox can not be set together")
++        
++        if bbox:
++            ograpi.OGR_L_SetSpatialFilterRect(
++                cogr_layer, bbox[0], bbox[1], bbox[2], bbox[3])
++        elif mask:
++            cogr_geometry = OGRGeomBuilder().build(mask)
++            ograpi.OGR_L_SetSpatialFilter(cogr_layer, cogr_geometry)
++            ograpi.OGR_G_DestroyGeometry(cogr_geometry)
++            
++        else:
++            ograpi.OGR_L_SetSpatialFilter(
++                cogr_layer, NULL)
++        self.encoding = session.get_internalencoding()
++
++        self.fastindex = ograpi.OGR_L_TestCapability(
++            session.cogr_layer, OLC_FASTSETNEXTBYINDEX)
++
++        ftcount = ograpi.OGR_L_GetFeatureCount(session.cogr_layer, 0)
++        if ftcount == -1 and ((start is not None and start < 0) or
++                              (stop is not None and stop < 0)):
++            raise IndexError(
++                "collection's dataset does not support negative slice indexes")
++
++        if stop is not None and stop < 0:
++            stop += ftcount
++
++        if start is None:
++            start = 0
++        if start is not None and start < 0:
++            start += ftcount
++
++        # step size
++        if step is None:
++            step = 1
++        if step == 0:
++            raise ValueError("slice step cannot be zero")
++        if step < 0 and not self.fastindex:
++            warnings.warn("Layer does not support" \
++                    "OLCFastSetNextByIndex, negative step size may" \
++                    " be slow", RuntimeWarning)
++        self.stepsign = int(math.copysign(1, step))
++        self.stop = stop
++        self.start = start
++        self.step = step
++
++        self.next_index = start
++        log.debug("Index: %d", self.next_index)
++        ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++
++
++    def __iter__(self):
++        return self
++
++
++    def _next(self):
++        """Internal method to set read cursor to next item"""
++
++        cdef Session session
++        session = self.collection.session
++
++        # Check if next_index is valid
++        if self.next_index < 0:
++            raise StopIteration
++        
++        if self.stepsign == 1:
++            if self.next_index < self.start or (self.stop is not None and self.next_index >= self.stop):
++                raise StopIteration
++        else:
++            if self.next_index > self.start or (self.stop is not None and self.next_index <= self.stop):
++                raise StopIteration
++
++
++        # Set read cursor to next_item position
++        if self.step > 1 and self.fastindex:
++            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++
++        elif self.step > 1 and not self.fastindex and not self.next_index == self.start:
++            for _ in range(self.step - 1):
++                # TODO rbuffat add test -> OGR_L_GetNextFeature increments cursor by 1, therefore self.step - 1 as one increment was performed when feature is read
++                cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++                if cogr_feature == NULL:
++                    raise StopIteration
++        elif self.step > 1 and not self.fastindex and self.next_index == self.start:
++            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++
++        elif self.step == 0:
++            # ograpi.OGR_L_GetNextFeature increments read cursor by one
++            pass
++        elif self.step < 0:
++            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++            
++        # set the next index
++        self.next_index += self.step
++
++
++    def __next__(self):
++        cdef void * cogr_feature
++        cdef Session session
++        session = self.collection.session
++
++        #Update read cursor
++        self._next()
++
++        # Get the next feature.
++        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++        if cogr_feature == NULL:
++            raise StopIteration
++
++        feature = FeatureBuilder().build(
++            cogr_feature,
++            bbox=False,
++            encoding=self.encoding,
++            driver=self.collection.driver
++        )
++        _deleteOgrFeature(cogr_feature)
++        return feature
++
++
++cdef class ItemsIterator(Iterator):
++
++    def __next__(self):
++
++        cdef long fid
++        cdef void * cogr_feature
++        cdef Session session
++        session = self.collection.session
++
++        #Update read cursor
++        self._next()
++
++        # Get the next feature.
++        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++        if cogr_feature == NULL:
++            raise StopIteration
++
++
++        fid = ograpi.OGR_F_GetFID(cogr_feature)
++        feature = FeatureBuilder().build(
++            cogr_feature,
++            bbox=False,
++            encoding=self.encoding,
++            driver=self.collection.driver
++        )
++        _deleteOgrFeature(cogr_feature)
++
++        return fid, feature
++
++
++cdef class KeysIterator(Iterator):
++
++    def __next__(self):
++        cdef long fid
++        cdef void * cogr_feature
++        cdef Session session
++        session = self.collection.session
++
++        #Update read cursor
++        self._next()
++
++        # Get the next feature.
++        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++        if cogr_feature == NULL:
++            raise StopIteration
++
++        fid = ograpi.OGR_F_GetFID(cogr_feature)
++        _deleteOgrFeature(cogr_feature)
++
++        return fid
++
++
++def _listlayers(path):
++
++    """Provides a list of the layers in an OGR data source.
++    """
++    
++    cdef void *cogr_ds
++    cdef void *cogr_layer
++    cdef char *path_c
++    cdef char *name_c
++    
++    # Open OGR data source.
++    try:
++        path_b = path.encode('utf-8')
++    except UnicodeDecodeError:
++        path_b = path
++    path_c = path_b
++    with cpl_errs:
++        cogr_ds = ograpi.OGROpen(path_c, 0, NULL)
++    if cogr_ds == NULL:
++        raise ValueError("No data available at path '%s'" % path)
++    
++    # Loop over the layers to get their names.
++    layer_count = ograpi.OGR_DS_GetLayerCount(cogr_ds)
++    layer_names = []
++    for i in range(layer_count):
++        cogr_layer = ograpi.OGR_DS_GetLayer(cogr_ds, i)
++        name_c = ograpi.OGR_L_GetName(cogr_layer)
++        name_b = name_c
++        layer_names.append(name_b.decode('utf-8'))
++    
++    # Close up data source.
++    if cogr_ds is not NULL:
++        ograpi.OGR_DS_Destroy(cogr_ds)
++    cogr_ds = NULL
++
++    return layer_names
++
++def buffer_to_virtual_file(bytesbuf):
++    """Maps a bytes buffer to a virtual file.
++    """
++    vsi_filename = os.path.join('/vsimem', uuid.uuid4().hex)
++    vsi_cfilename = vsi_filename if not isinstance(vsi_filename, string_types) else vsi_filename.encode('utf-8')
++
++    vsi_handle = ograpi.VSIFileFromMemBuffer(vsi_cfilename, bytesbuf, len(bytesbuf), 0)
++    if vsi_handle == NULL:
++        raise OSError('failed to map buffer to file')
++    if ograpi.VSIFCloseL(vsi_handle) != 0:
++        raise OSError('failed to close mapped file handle')
++
++    return vsi_filename
++
++def remove_virtual_file(vsi_filename):
++    vsi_cfilename = vsi_filename if not isinstance(vsi_filename, string_types) else vsi_filename.encode('utf-8')
++    return ograpi.VSIUnlink(vsi_cfilename)
++
++
+--- /dev/null
++++ b/fiona/ogrext2.pyx
+@@ -0,0 +1,1307 @@
++# These are extension functions and classes using the OGR C API.
++
++import datetime
++import json
++import locale
++import logging
++import os
++import sys
++import warnings
++import math
++import uuid
++
++from six import integer_types, string_types, text_type
++
++from fiona cimport ograpi
++from fiona._geometry cimport GeomBuilder, OGRGeomBuilder
++from fiona._err import cpl_errs
++from fiona._geometry import GEOMETRY_TYPES
++from fiona.errors import DriverError, SchemaError, CRSError, FionaValueError
++from fiona.odict import OrderedDict
++from fiona.rfc3339 import parse_date, parse_datetime, parse_time
++from fiona.rfc3339 import FionaDateType, FionaDateTimeType, FionaTimeType
++
++from libc.stdlib cimport malloc, free
++from libc.string cimport strcmp
++from builtins import int
++
++log = logging.getLogger("Fiona")
++class NullHandler(logging.Handler):
++    def emit(self, record):
++        pass
++log.addHandler(NullHandler())
++
++
++# Mapping of OGR integer field types to Fiona field type names.
++#
++# Lists are currently unsupported in this version, but might be done as
++# arrays in a future version.
++
++FIELD_TYPES = [
++    'int',          # OFTInteger, Simple 32bit integer
++    None,           # OFTIntegerList, List of 32bit integers
++    'float',        # OFTReal, Double Precision floating point
++    None,           # OFTRealList, List of doubles
++    'str',          # OFTString, String of ASCII chars
++    None,           # OFTStringList, Array of strings
++    None,           # OFTWideString, deprecated
++    None,           # OFTWideStringList, deprecated
++    None,           # OFTBinary, Raw Binary data
++    'date',         # OFTDate, Date
++    'time',         # OFTTime, Time
++    'datetime',     # OFTDateTime, Date and Time
++    'int',          # OFTInteger64, Single 64bit integer
++    None,           # OFTInteger64List, List of 64bit integers
++    ]
++
++# Mapping of Fiona field type names to Python types.
++FIELD_TYPES_MAP = {
++    'int':      int,
++    'float':    float,
++    'str':      text_type,
++    'date':     FionaDateType,
++    'time':     FionaTimeType,
++    'datetime': FionaDateTimeType
++   }
++
++# OGR Layer capability
++OLC_RANDOMREAD = b"RandomRead"
++OLC_SEQUENTIALWRITE = b"SequentialWrite"
++OLC_RANDOMWRITE = b"RandomWrite"
++OLC_FASTSPATIALFILTER = b"FastSpatialFilter"
++OLC_FASTFEATURECOUNT = b"FastFeatureCount"
++OLC_FASTGETEXTENT = b"FastGetExtent"
++OLC_FASTSETNEXTBYINDEX = b"FastSetNextByIndex"
++OLC_CREATEFIELD = b"CreateField"
++OLC_CREATEGEOMFIELD = b"CreateGeomField"
++OLC_DELETEFIELD = b"DeleteField"
++OLC_REORDERFIELDS = b"ReorderFields"
++OLC_ALTERFIELDDEFN = b"AlterFieldDefn"
++OLC_DELETEFEATURE = b"DeleteFeature"
++OLC_STRINGSASUTF8 = b"StringsAsUTF8"
++OLC_TRANSACTIONS = b"Transactions"
++
++# OGR integer error types.
++
++OGRERR_NONE = 0
++OGRERR_NOT_ENOUGH_DATA = 1    # not enough data to deserialize */
++OGRERR_NOT_ENOUGH_MEMORY = 2
++OGRERR_UNSUPPORTED_GEOMETRY_TYPE = 3
++OGRERR_UNSUPPORTED_OPERATION = 4
++OGRERR_CORRUPT_DATA = 5
++OGRERR_FAILURE = 6
++OGRERR_UNSUPPORTED_SRS = 7
++OGRERR_INVALID_HANDLE = 8
++
++
++cdef char ** string_list(list_str):
++    """
++    Function by Stackoverflow User falsetru
++    https://stackoverflow.com/questions/17511309/fast-string-array-cython
++    """
++    cdef char* s
++    cdef char **ret = <char **>malloc(len(list_str) * sizeof(char *))
++    for i in range(len(list_str)):
++        s = list_str[i]
++        ret[i] = s
++    ret[i + 1] = NULL
++    return ret
++
++def _explode(coords):
++    """Explode a GeoJSON geometry's coordinates object and yield
++    coordinate tuples. As long as the input is conforming, the type of
++    the geometry doesn't matter."""
++    for e in coords:
++        if isinstance(e, (float, int)):
++            yield coords
++            break
++        else:
++            for f in _explode(e):
++                yield f
++
++
++def _bounds(geometry):
++    """Bounding box of a GeoJSON geometry"""
++    try:
++        xyz = tuple(zip(*list(_explode(geometry['coordinates']))))
++        return min(xyz[0]), min(xyz[1]), max(xyz[0]), max(xyz[1])
++    except (KeyError, TypeError):
++        return None
++
++def calc_gdal_version_num(maj, min, rev):
++    """Calculates the internal gdal version number based on major, minor and revision"""
++    return int(maj * 1000000 + min * 10000 + rev*100)
++
++def get_gdal_version_num():
++    """Return current internal version number of gdal"""
++    return int(ograpi.GDALVersionInfo("VERSION_NUM"))
++
++def get_gdal_release_name():
++    """Return release name of gdal"""
++    return ograpi.GDALVersionInfo("RELEASE_NAME")
++
++
++# Feature extension classes and functions follow.
++
++cdef class FeatureBuilder:
++    """Build Fiona features from OGR feature pointers.
++
++    No OGR objects are allocated by this function and the feature
++    argument is not destroyed.
++    """
++
++    cdef build(self, void *feature, encoding='utf-8', bbox=False, driver=None):
++        # The only method anyone ever needs to call
++        cdef void *fdefn
++        cdef int i
++        cdef int y = 0
++        cdef int m = 0
++        cdef int d = 0
++        cdef int hh = 0
++        cdef int mm = 0
++        cdef int ss = 0
++        cdef int tz = 0
++        cdef int retval
++        cdef char *key_c
++        props = OrderedDict()
++        for i in range(ograpi.OGR_F_GetFieldCount(feature)):
++            fdefn = ograpi.OGR_F_GetFieldDefnRef(feature, i)
++            if fdefn == NULL:
++                raise ValueError("Null feature definition")
++            key_c = ograpi.OGR_Fld_GetNameRef(fdefn)
++            if key_c == NULL:
++                raise ValueError("Null field name reference")
++            key_b = key_c
++            key = key_b.decode(encoding)
++            fieldtypename = FIELD_TYPES[ograpi.OGR_Fld_GetType(fdefn)]
++            if not fieldtypename:
++                log.warn(
++                    "Skipping field %s: invalid type %s", 
++                    key,
++                    ograpi.OGR_Fld_GetType(fdefn))
++                continue
++
++            # TODO: other types
++            fieldtype = FIELD_TYPES_MAP[fieldtypename]
++            if not ograpi.OGR_F_IsFieldSet(feature, i):
++                props[key] = None
++            elif fieldtype is int:
++                props[key] = ograpi.OGR_F_GetFieldAsInteger64(feature, i)
++            elif fieldtype is float:
++                props[key] = ograpi.OGR_F_GetFieldAsDouble(feature, i)
++
++            elif fieldtype is text_type:
++                try:
++                    val = ograpi.OGR_F_GetFieldAsString(feature, i)
++                    val = val.decode(encoding)
++                except UnicodeDecodeError:
++                    log.warn(
++                        "Failed to decode %s using %s codec", val, encoding)
++
++                # Does the text contain a JSON object? Let's check.
++                # Let's check as cheaply as we can.
++                if driver == 'GeoJSON' and val.startswith('{'):
++                    try:
++                        val = json.loads(val)
++                    except ValueError as err:
++                        log.warn(str(err))
++
++                # Now add to the properties object.
++                props[key] = val
++
++            elif fieldtype in (FionaDateType, FionaTimeType, FionaDateTimeType):
++                retval = ograpi.OGR_F_GetFieldAsDateTime(
++                    feature, i, &y, &m, &d, &hh, &mm, &ss, &tz)
++                if fieldtype is FionaDateType:
++                    props[key] = datetime.date(y, m, d).isoformat()
++                elif fieldtype is FionaTimeType:
++                    props[key] = datetime.time(hh, mm, ss).isoformat()
++                else:
++                    props[key] = datetime.datetime(
++                        y, m, d, hh, mm, ss).isoformat()
++            else:
++                log.debug("%s: None, fieldtype: %r, %r" % (key, fieldtype, fieldtype in string_types))
++                props[key] = None
++
++        cdef void *cogr_geometry = ograpi.OGR_F_GetGeometryRef(feature)
++        if cogr_geometry is not NULL:
++            geom = GeomBuilder().build(cogr_geometry)
++        else:
++            geom = None
++        return {
++            'type': 'Feature',
++            'id': str(ograpi.OGR_F_GetFID(feature)),
++            'geometry': geom,
++            'properties': props }
++
++
++cdef class OGRFeatureBuilder:
++    
++    """Builds an OGR Feature from a Fiona feature mapping.
++
++    Allocates one OGR Feature which should be destroyed by the caller.
++    Borrows a layer definition from the collection.
++    """
++    
++    cdef void * build(self, feature, collection) except NULL:
++        cdef void *cogr_geometry = NULL
++        cdef char *string_c
++        cdef WritingSession session
++        session = collection.session
++        cdef void *cogr_layer = session.cogr_layer
++        if cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cdef void *cogr_featuredefn = ograpi.OGR_L_GetLayerDefn(cogr_layer)
++        if cogr_featuredefn == NULL:
++            raise ValueError("Null feature definition")
++        cdef void *cogr_feature = ograpi.OGR_F_Create(cogr_featuredefn)
++        if cogr_feature == NULL:
++            raise ValueError("Null feature")
++        
++        if feature['geometry'] is not None:
++            cogr_geometry = OGRGeomBuilder().build(
++                                feature['geometry'])
++        ograpi.OGR_F_SetGeometryDirectly(cogr_feature, cogr_geometry)
++        
++        # OGR_F_SetFieldString takes UTF-8 encoded strings ('bytes' in 
++        # Python 3).
++        encoding = session.get_internalencoding()
++
++        for key, value in feature['properties'].items():
++            log.debug(
++                "Looking up %s in %s", key, repr(session._schema_mapping))
++            ogr_key = session._schema_mapping[key]
++            schema_type = collection.schema['properties'][key]
++            try:
++                key_bytes = ogr_key.encode(encoding)
++            except UnicodeDecodeError:
++                log.warn("Failed to encode %s using %s codec", key, encoding)
++                key_bytes = ogr_key
++            key_c = key_bytes
++            i = ograpi.OGR_F_GetFieldIndex(cogr_feature, key_c)
++            if i < 0:
++                continue
++
++            # Special case: serialize dicts to assist OGR.
++            if isinstance(value, dict):
++                value = json.dumps(value)
++
++            # Continue over the standard OGR types.
++            if isinstance(value, integer_types):
++                ograpi.OGR_F_SetFieldInteger64(cogr_feature, i, value)
++            elif isinstance(value, float):
++                ograpi.OGR_F_SetFieldDouble(cogr_feature, i, value)
++            elif (isinstance(value, string_types) 
++            and schema_type in ['date', 'time', 'datetime']):
++                if schema_type == 'date':
++                    y, m, d, hh, mm, ss, ff = parse_date(value)
++                elif schema_type == 'time':
++                    y, m, d, hh, mm, ss, ff = parse_time(value)
++                else:
++                    y, m, d, hh, mm, ss, ff = parse_datetime(value)
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, y, m, d, hh, mm, ss, 0)
++            elif (isinstance(value, datetime.date)
++            and schema_type == 'date'):
++                y, m, d = value.year, value.month, value.day
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, y, m, d, 0, 0, 0, 0)
++            elif (isinstance(value, datetime.datetime)
++            and schema_type == 'datetime'):
++                y, m, d = value.year, value.month, value.day
++                hh, mm, ss = value.hour, value.minute, value.second
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, y, m, d, hh, mm, ss, 0)
++            elif (isinstance(value, datetime.time)
++            and schema_type == 'time'):
++                hh, mm, ss = value.hour, value.minute, value.second
++                ograpi.OGR_F_SetFieldDateTime(
++                    cogr_feature, i, 0, 0, 0, hh, mm, ss, 0)
++            elif isinstance(value, string_types):
++                try:
++                    value_bytes = value.encode(encoding)
++                except UnicodeDecodeError:
++                    log.warn(
++                        "Failed to encode %s using %s codec", value, encoding)
++                    value_bytes = value
++                string_c = value_bytes
++                ograpi.OGR_F_SetFieldString(cogr_feature, i, string_c)
++            elif value is None:
++                pass # keep field unset/null
++            else:
++                raise ValueError("Invalid field type %s" % type(value))
++            log.debug("Set field %s: %s" % (key, value))
++        return cogr_feature
++
++
++cdef _deleteOgrFeature(void *cogr_feature):
++    """Delete an OGR feature"""
++    if cogr_feature is not NULL:
++        ograpi.OGR_F_Destroy(cogr_feature)
++    cogr_feature = NULL
++
++
++def featureRT(feature, collection):
++    # For testing purposes only, leaks the JSON data
++    cdef void *cogr_feature = OGRFeatureBuilder().build(feature, collection)
++    cdef void *cogr_geometry = ograpi.OGR_F_GetGeometryRef(cogr_feature)
++    if cogr_geometry == NULL:
++        raise ValueError("Null geometry")
++    log.debug("Geometry: %s" % ograpi.OGR_G_ExportToJson(cogr_geometry))
++    encoding = collection.encoding or 'utf-8'
++    result = FeatureBuilder().build(
++        cogr_feature,
++        bbox=False,
++        encoding=encoding,
++        driver=collection.driver
++    )
++    _deleteOgrFeature(cogr_feature)
++    return result
++
++
++# Collection-related extension classes and functions
++
++cdef class Session:
++    
++    cdef void *cogr_ds
++    cdef void *cogr_layer
++    cdef object _fileencoding
++    cdef object _encoding
++    cdef object collection
++
++    def __cinit__(self):
++        self.cogr_ds = NULL
++        self.cogr_layer = NULL
++        self._fileencoding = None
++        self._encoding = None
++
++    def __dealloc__(self):
++        self.stop()
++
++    def start(self, collection):
++        cdef const char *path_c = NULL
++        cdef const char *name_c = NULL
++        cdef void *drv = NULL
++        cdef void *ds = NULL
++        cdef char ** drvs = NULL
++        if collection.path == '-':
++            path = '/vsistdin/'
++        else:
++            path = collection.path
++        try:
++            path_b = path.encode('utf-8')
++        except UnicodeDecodeError:
++            # Presume already a UTF-8 encoded string
++            path_b = path
++        path_c = path_b
++        
++        with cpl_errs:
++            drivers = []
++            if collection._driver:
++                drivers = [collection._driver]
++            elif collection.enabled_drivers:
++                drivers = collection.enabled_drivers
++            if drivers:
++                for name in drivers:
++                    name_b = name.encode()
++                    name_c = name_b
++                    log.debug("Trying driver: %s", name)
++                    drv = ograpi.GDALGetDriverByName(name_c)
++                    if drv != NULL:
++                        drvs = string_list([name_b])
++
++                        flags = ograpi.GDAL_OF_VECTOR | ograpi.GDAL_OF_READONLY
++                        log.debug("GDALOpenEx({}, {}, {})".format(path_c, flags, [name_b]))
++                        ds = ograpi.GDALOpenEx(path_c,
++                                               flags,
++                                               drvs,
++                                               NULL,
++                                               NULL)
++                    if ds != NULL:
++                        self.cogr_ds = ds
++                        collection._driver = name
++                        _driver = ograpi.GDALGetDatasetDriver(ds)
++                        drv_name = ograpi.GDALGetDriverShortName(_driver)
++                        log.debug("Driver: {} Success".format(drv_name))
++
++                        break
++            else:
++                self.cogr_ds = ograpi.GDALOpenEx(path_c,
++                                                 ograpi.GDAL_OF_VECTOR | ograpi.GDAL_OF_READONLY,
++                                                 NULL,
++                                                 NULL,
++                                                 NULL)
++
++        if self.cogr_ds == NULL:
++            raise FionaValueError(
++                "No dataset found at path '%s' using drivers: %s" % (
++                    collection.path,
++                    drivers or '*'))
++        
++        if isinstance(collection.name, string_types):
++            name_b = collection.name.encode('utf-8')
++            name_c = name_b
++            self.cogr_layer = ograpi.GDALDatasetGetLayerByName(
++                                self.cogr_ds, name_c)
++        elif isinstance(collection.name, int):
++            self.cogr_layer = ograpi.GDALDatasetGetLayer(
++                                self.cogr_ds, collection.name)
++            name_c = ograpi.OGR_L_GetName(self.cogr_layer)
++            name_b = name_c
++            collection.name = name_b.decode('utf-8')
++
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer: " + repr(collection.name))
++        
++        self.collection = collection
++        
++        userencoding = self.collection.encoding
++        if userencoding:
++            ograpi.CPLSetThreadLocalConfigOption('SHAPE_ENCODING', '')
++            self._fileencoding = userencoding.upper()
++        else:
++            self._fileencoding = (
++                ograpi.OGR_L_TestCapability(
++                    self.cogr_layer, OLC_STRINGSASUTF8) and
++                'utf-8') or (
++                self.get_driver() == "ESRI Shapefile" and
++                'ISO-8859-1') or locale.getpreferredencoding().upper()
++
++    def stop(self):
++        self.cogr_layer = NULL
++        if self.cogr_ds is not NULL:
++            ograpi.GDALClose(self.cogr_ds)
++        self.cogr_ds = NULL
++
++    def get_fileencoding(self):
++        return self._fileencoding
++
++    def get_internalencoding(self):
++        if not self._encoding:
++            fileencoding = self.get_fileencoding()
++            self._encoding = (
++                ograpi.OGR_L_TestCapability(
++                    self.cogr_layer, OLC_STRINGSASUTF8) and
++                'utf-8') or fileencoding
++        return self._encoding
++
++    def get_length(self):
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        return ograpi.OGR_L_GetFeatureCount(self.cogr_layer, 0)
++
++    def get_driver(self):
++        cdef void *cogr_driver = ograpi.GDALGetDatasetDriver(self.cogr_ds)
++        if cogr_driver == NULL:
++            raise ValueError("Null driver")
++        cdef char *name = ograpi.OGR_Dr_GetName(cogr_driver)
++        driver_name = name
++        return driver_name.decode()
++ 
++    def get_schema(self):
++        cdef int i
++        cdef int n
++        cdef void *cogr_featuredefn
++        cdef void *cogr_fielddefn
++        cdef char *key_c
++        props = []
++        
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++
++        cogr_featuredefn = ograpi.OGR_L_GetLayerDefn(self.cogr_layer)
++        if cogr_featuredefn == NULL:
++            raise ValueError("Null feature definition")
++        n = ograpi.OGR_FD_GetFieldCount(cogr_featuredefn)
++        for i from 0 <= i < n:
++            cogr_fielddefn = ograpi.OGR_FD_GetFieldDefn(cogr_featuredefn, i)
++            if cogr_fielddefn == NULL:
++                raise ValueError("Null field definition")
++            key_c = ograpi.OGR_Fld_GetNameRef(cogr_fielddefn)
++            key_b = key_c
++            if not bool(key_b):
++                raise ValueError("Invalid field name ref: %s" % key)
++            key = key_b.decode(self.get_internalencoding())
++            fieldtypename = FIELD_TYPES[ograpi.OGR_Fld_GetType(cogr_fielddefn)]
++            if not fieldtypename:
++                log.warn(
++                    "Skipping field %s: invalid type %s", 
++                    key,
++                    ograpi.OGR_Fld_GetType(cogr_fielddefn))
++                continue
++            val = fieldtypename
++            if fieldtypename == 'float':
++                fmt = ""
++                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
++                if width: # and width != 24:
++                    fmt = ":%d" % width
++                precision = ograpi.OGR_Fld_GetPrecision(cogr_fielddefn)
++                if precision: # and precision != 15:
++                    fmt += ".%d" % precision
++                val = "float" + fmt
++            elif fieldtypename == 'int':
++                fmt = ""
++                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
++                if width: # and width != 11:
++                    fmt = ":%d" % width
++                val = fieldtypename + fmt
++            elif fieldtypename == 'str':
++                fmt = ""
++                width = ograpi.OGR_Fld_GetWidth(cogr_fielddefn)
++                if width: # and width != 80:
++                    fmt = ":%d" % width
++                val = fieldtypename + fmt
++
++            props.append((key, val))
++
++        cdef unsigned int geom_type = ograpi.OGR_FD_GetGeomType(
++            cogr_featuredefn)
++        return {
++            'properties': OrderedDict(props), 
++            'geometry': GEOMETRY_TYPES[geom_type]}
++
++    def get_crs(self):
++        cdef char *proj_c = NULL
++        cdef char *auth_key = NULL
++        cdef char *auth_val = NULL
++        cdef void *cogr_crs = NULL
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cogr_crs = ograpi.OGR_L_GetSpatialRef(self.cogr_layer)
++        crs = {}
++        if cogr_crs is not NULL:
++            log.debug("Got coordinate system")
++
++            retval = ograpi.OSRAutoIdentifyEPSG(cogr_crs)
++            if retval > 0:
++                log.info("Failed to auto identify EPSG: %d", retval)
++            
++            auth_key = ograpi.OSRGetAuthorityName(cogr_crs, NULL)
++            auth_val = ograpi.OSRGetAuthorityCode(cogr_crs, NULL)
++
++            if auth_key != NULL and auth_val != NULL:
++                key_b = auth_key
++                key = key_b.decode('utf-8')
++                if key == 'EPSG':
++                    val_b = auth_val
++                    val = val_b.decode('utf-8')
++                    crs['init'] = "epsg:" + val
++            else:
++                ograpi.OSRExportToProj4(cogr_crs, &proj_c)
++                if proj_c == NULL:
++                    raise ValueError("Null projection")
++                proj_b = proj_c
++                log.debug("Params: %s", proj_b)
++                value = proj_b.decode()
++                value = value.strip()
++                for param in value.split():
++                    kv = param.split("=")
++                    if len(kv) == 2:
++                        k, v = kv
++                        try:
++                            v = float(v)
++                            if v % 1 == 0:
++                                v = int(v)
++                        except ValueError:
++                            # Leave v as a string
++                            pass
++                    elif len(kv) == 1:
++                        k, v = kv[0], True
++                    else:
++                        raise ValueError("Unexpected proj parameter %s" % param)
++                    k = k.lstrip("+")
++                    crs[k] = v
++
++            ograpi.CPLFree(proj_c)
++        else:
++            log.debug("Projection not found (cogr_crs was NULL)")
++        return crs
++
++    def get_crs_wkt(self):
++        cdef char *proj_c = NULL
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cogr_crs = ograpi.OGR_L_GetSpatialRef(self.cogr_layer)
++        crs_wkt = ""
++        if cogr_crs is not NULL:
++            log.debug("Got coordinate system")
++            ograpi.OSRExportToWkt(cogr_crs, &proj_c)
++            if proj_c == NULL:
++                raise ValueError("Null projection")
++            proj_b = proj_c
++            crs_wkt = proj_b.decode('utf-8')
++            ograpi.CPLFree(proj_c)
++        else:
++            log.debug("Projection not found (cogr_crs was NULL)")        
++        return crs_wkt
++
++    def get_extent(self):
++        if self.cogr_layer == NULL:
++            raise ValueError("Null layer")
++        cdef ograpi.OGREnvelope extent
++        result = ograpi.OGR_L_GetExtent(self.cogr_layer, &extent, 1)
++        return (extent.MinX, extent.MinY, extent.MaxX, extent.MaxY)
++
++    def has_feature(self, fid):
++        """Provides access to feature data by FID.
++
++        Supports Collection.__contains__().
++        """
++        cdef void * cogr_feature
++        fid = int(fid)
++        cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, fid)
++        if cogr_feature != NULL:
++            _deleteOgrFeature(cogr_feature)
++            return True
++        else:
++            return False
++
++    def get_feature(self, fid):
++        """Provides access to feature data by FID.
++
++        Supports Collection.__contains__().
++        """
++        cdef void * cogr_feature
++        fid = int(fid)
++        cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, fid)
++        if cogr_feature != NULL:
++            _deleteOgrFeature(cogr_feature)
++            return True
++        else:
++            return False
++
++
++    def __getitem__(self, item):
++        cdef void * cogr_feature
++        if isinstance(item, slice):
++            itr = Iterator(self.collection, item.start, item.stop, item.step)
++            log.debug("Slice: %r", item)
++            return list(itr)
++        elif isinstance(item, int):
++            index = item
++            # from the back
++            if index < 0:
++                ftcount = ograpi.OGR_L_GetFeatureCount(self.cogr_layer, 0)
++                if ftcount == -1:
++                    raise IndexError(
++                        "collection's dataset does not support negative indexes")
++                index += ftcount
++            cogr_feature = ograpi.OGR_L_GetFeature(self.cogr_layer, index)
++            if cogr_feature == NULL:
++                return None
++            feature = FeatureBuilder().build(
++                cogr_feature,
++                bbox=False,
++                encoding=self.get_internalencoding(),
++                driver=self.collection.driver
++            )
++            _deleteOgrFeature(cogr_feature)
++            return feature
++
++
++    def isactive(self):
++        if self.cogr_layer != NULL and self.cogr_ds != NULL:
++            return 1
++        else:
++            return 0
++
++
++cdef class WritingSession(Session):
++    
++    cdef object _schema_mapping
++
++    def start(self, collection):
++        cdef void *cogr_fielddefn
++        cdef void *cogr_driver
++        cdef void *cogr_ds
++        cdef void *cogr_layer
++        cdef void *cogr_srs = NULL
++        cdef char **options = NULL
++        self.collection = collection
++        cdef char *path_c
++        cdef char *driver_c
++        cdef char *name_c
++        cdef char *proj_c
++        cdef char *fileencoding_c
++        path = collection.path
++
++        if collection.mode == 'a':
++            if os.path.exists(path):
++                try:
++                    path_b = path.encode('utf-8')
++                except UnicodeDecodeError:
++                    path_b = path
++                path_c = path_b
++                with cpl_errs:
++                    self.cogr_ds = ograpi.GDALOpenEx(path_c,
++                                                 ograpi.GDAL_OF_VECTOR | ograpi.GDAL_OF_UPDATE,
++                                                 NULL,
++                                                 NULL,
++                                                 NULL)
++#                     self.cogr_ds = ograpi.OGROpen(path_c, 1, NULL)
++                if self.cogr_ds == NULL:
++                    raise RuntimeError("Failed to open %s" % path)
++                cogr_driver = ograpi.GDALGetDatasetDriver(self.cogr_ds)
++                if cogr_driver == NULL:
++                    raise ValueError("Null driver")
++
++                if isinstance(collection.name, string_types):
++                    name_b = collection.name.encode()
++                    name_c = name_b
++                    self.cogr_layer = ograpi.GDALDatasetGetLayerByName(
++                                        self.cogr_ds, name_c)
++                elif isinstance(collection.name, int):
++                    self.cogr_layer = ograpi.GDALDatasetGetLayer(
++                                        self.cogr_ds, collection.name)
++
++                if self.cogr_layer == NULL:
++                    raise RuntimeError(
++                        "Failed to get layer %s" % collection.name)
++            else:
++                raise OSError("No such file or directory %s" % path)
++
++            userencoding = self.collection.encoding
++            self._fileencoding = (userencoding or (
++                ograpi.OGR_L_TestCapability(self.cogr_layer, OLC_STRINGSASUTF8) and
++                'utf-8') or (
++                self.get_driver() == "ESRI Shapefile" and
++                'ISO-8859-1') or locale.getpreferredencoding()).upper()
++
++        elif collection.mode == 'w':
++            try:
++                path_b = path.encode('utf-8')
++            except UnicodeDecodeError:
++                path_b = path
++            path_c = path_b
++            driver_b = collection.driver.encode()
++            driver_c = driver_b
++
++            cogr_driver = ograpi.GDALGetDriverByName(driver_c)
++            if cogr_driver == NULL:
++                raise ValueError("Null driver")
++
++            if not os.path.exists(path):
++#                 cogr_ds = ograpi.OGR_Dr_CreateDataSource(
++#                     cogr_driver, path_c, NULL)
++                cogr_ds = ograpi.GDALCreate(
++                    cogr_driver,
++                    path_c,
++                    0,
++                    0,
++                    0,
++                    ograpi.GDT_Unknown,
++                    NULL)
++                pass
++
++            else:
++                with cpl_errs:
++                    cogr_ds = ograpi.GDALOpenEx(path_c,
++                                     ograpi.GDAL_OF_VECTOR | ograpi.GDAL_OF_UPDATE,
++                                     NULL,
++                                     NULL,
++                                     NULL)
++#                     cogr_ds = ograpi.OGROpen(path_c, 1, NULL)
++                if cogr_ds == NULL:
++                    cogr_ds = ograpi.GDALCreate(
++                        cogr_driver,
++                        path_c,
++                        0,
++                        0,
++                        0,
++                        ograpi.GDT_Unknown,
++                        NULL)
++#                     cogr_ds = ograpi.OGR_Dr_CreateDataSource(
++#                         cogr_driver, path_c, NULL)
++
++                elif collection.name is None:
++                    ograpi.GDALClose(cogr_ds)
++                    cogr_ds == NULL
++                    log.debug("Deleted pre-existing data at %s", path)
++                    cogr_ds = ograpi.GDALCreate(
++                        cogr_driver,
++                        path_c,
++                        0,
++                        0,
++                        0,
++                        ograpi.GDT_Unknown,
++                        NULL)
++#                     cogr_ds = ograpi.OGR_Dr_CreateDataSource(
++#                         cogr_driver, path_c, NULL)
++
++                else:
++                    pass
++
++            if cogr_ds == NULL:
++                raise RuntimeError("Failed to open %s" % path)
++            else:
++                self.cogr_ds = cogr_ds
++
++            # Set the spatial reference system from the crs given to the
++            # collection constructor. We by-pass the crs_wkt and crs
++            # properties because they aren't accessible until the layer
++            # is constructed (later).
++            col_crs = collection._crs_wkt or collection._crs
++            if col_crs:
++                cogr_srs = ograpi.OSRNewSpatialReference(NULL)
++                if cogr_srs == NULL:
++                    raise ValueError("NULL spatial reference")
++                # First, check for CRS strings like "EPSG:3857".
++                if isinstance(col_crs, string_types):
++                    proj_b = col_crs.encode('utf-8')
++                    proj_c = proj_b
++                    ograpi.OSRSetFromUserInput(cogr_srs, proj_c)
++                elif isinstance(col_crs, dict):
++                    # EPSG is a special case.
++                    init = col_crs.get('init')
++                    if init:
++                        log.debug("Init: %s", init)
++                        auth, val = init.split(':')
++                        if auth.upper() == 'EPSG':
++                            log.debug("Setting EPSG: %s", val)
++                            ograpi.OSRImportFromEPSG(cogr_srs, int(val))
++                    else:
++                        params = []
++                        col_crs['wktext'] = True
++                        for k, v in col_crs.items():
++                            if v is True or (k in ('no_defs', 'wktext') and v):
++                                params.append("+%s" % k)
++                            else:
++                                params.append("+%s=%s" % (k, v))
++                        proj = " ".join(params)
++                        log.debug("PROJ.4 to be imported: %r", proj)
++                        proj_b = proj.encode('utf-8')
++                        proj_c = proj_b
++                        ograpi.OSRImportFromProj4(cogr_srs, proj_c)
++                else:
++                    raise ValueError("Invalid CRS")
++
++                # Fixup, export to WKT, and set the GDAL dataset's projection.
++                ograpi.OSRFixup(cogr_srs)
++
++            # Figure out what encoding to use. The encoding parameter given
++            # to the collection constructor takes highest precedence, then
++            # 'iso-8859-1', then the system's default encoding as last resort.
++            sysencoding = locale.getpreferredencoding()
++            userencoding = collection.encoding
++            self._fileencoding = (userencoding or (
++                collection.driver == "ESRI Shapefile" and
++                'ISO-8859-1') or sysencoding).upper()
++
++            fileencoding = self.get_fileencoding()
++            if fileencoding:
++                fileencoding_b = fileencoding.encode()
++                fileencoding_c = fileencoding_b
++                options = ograpi.CSLSetNameValue(options, "ENCODING", fileencoding_c)
++
++            # Does the layer exist already? If so, we delete it.
++            layer_count = ograpi.GDALDatasetGetLayerCount(self.cogr_ds)
++            layer_names = []
++            for i in range(layer_count):
++                cogr_layer = ograpi.GDALDatasetGetLayer(cogr_ds, i)
++                name_c = ograpi.OGR_L_GetName(cogr_layer)
++                name_b = name_c
++                layer_names.append(name_b.decode('utf-8'))
++
++            idx = -1
++            if isinstance(collection.name, string_types):
++                if collection.name in layer_names:
++                    idx = layer_names.index(collection.name)
++            elif isinstance(collection.name, int):
++                if collection.name >= 0 and collection.name < layer_count:
++                    idx = collection.name
++            if idx >= 0:
++                log.debug("Deleted pre-existing layer at %s", collection.name)
++                ograpi.GDALDatasetDeleteLayer(self.cogr_ds, idx)
++            
++            # Create the named layer in the datasource.
++            name_b = collection.name.encode('utf-8')
++            name_c = name_b
++            self.cogr_layer = ograpi.GDALDatasetCreateLayer(
++                self.cogr_ds, 
++                name_c,
++                cogr_srs,
++                <unsigned int>[k for k,v in GEOMETRY_TYPES.items() if 
++                    v == collection.schema.get('geometry', 'Unknown')][0],
++                options
++                )
++
++            if cogr_srs != NULL:
++                ograpi.OSRDestroySpatialReference(cogr_srs)
++            if options != NULL:
++                ograpi.CSLDestroy(options)
++
++            if self.cogr_layer == NULL:
++                raise ValueError("Null layer")
++            log.debug("Created layer")
++            
++            # Next, make a layer definition from the given schema properties,
++            # which are an ordered dict since Fiona 1.0.1.
++            for key, value in collection.schema['properties'].items():
++                log.debug("Creating field: %s %s", key, value)
++
++                # Convert 'long' to 'int'. See
++                # https://github.com/Toblerity/Fiona/issues/101.
++                if value == 'long':
++                    value = 'int'
++
++                # Is there a field width/precision?
++                width = precision = None
++                if ':' in value:
++                    value, fmt = value.split(':')
++                    if '.' in fmt:
++                        width, precision = map(int, fmt.split('.'))
++                    else:
++                        width = int(fmt)
++
++                field_type = FIELD_TYPES.index(value)
++                # See https://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
++                if value == 'int' and (width is not None and width >= 10):
++                    field_type = 12
++
++                encoding = self.get_internalencoding()
++                key_bytes = key.encode(encoding)
++
++                cogr_fielddefn = ograpi.OGR_Fld_Create(
++                    key_bytes,
++                    field_type)
++                if cogr_fielddefn == NULL:
++                    raise ValueError("Null field definition")
++                if width:
++                    ograpi.OGR_Fld_SetWidth(cogr_fielddefn, width)
++                if precision:
++                    ograpi.OGR_Fld_SetPrecision(cogr_fielddefn, precision)
++                ograpi.OGR_L_CreateField(self.cogr_layer, cogr_fielddefn, 1)
++                ograpi.OGR_Fld_Destroy(cogr_fielddefn)
++            log.debug("Created fields")
++
++        # Mapping of the Python collection schema to the munged 
++        # OGR schema.
++        ogr_schema = self.get_schema()
++        self._schema_mapping = dict(zip(
++            collection.schema['properties'].keys(), 
++            ogr_schema['properties'].keys() ))
++
++        log.debug("Writing started")
++
++    def writerecs(self, records, collection):
++        """Writes buffered records to OGR."""
++        cdef void *cogr_driver
++        cdef void *cogr_feature
++
++        cdef void *cogr_layer = self.cogr_layer
++        if cogr_layer == NULL:
++            raise ValueError("Null layer")
++    
++        schema_geom_type = collection.schema['geometry']
++        cogr_driver = ograpi.GDALGetDatasetDriver(self.cogr_ds)
++        if ograpi.OGR_Dr_GetName(cogr_driver) == b"GeoJSON":
++            def validate_geometry_type(rec):
++                return True
++        elif ograpi.OGR_Dr_GetName(cogr_driver) == b"ESRI Shapefile" \
++                and "Point" not in collection.schema['geometry']:
++            schema_geom_type = collection.schema['geometry'].lstrip(
++                "3D ").lstrip("Multi")
++            def validate_geometry_type(rec):
++                return rec['geometry'] is None or \
++                rec['geometry']['type'].lstrip(
++                    "3D ").lstrip("Multi") == schema_geom_type
++        else:
++            schema_geom_type = collection.schema['geometry'].lstrip("3D ")
++            def validate_geometry_type(rec):
++                return rec['geometry'] is None or \
++                       rec['geometry']['type'].lstrip("3D ") == schema_geom_type
++
++        schema_props_keys = set(collection.schema['properties'].keys())
++        for record in records:
++            log.debug("Creating feature in layer: %s" % record)
++            # Validate against collection's schema.
++            if set(record['properties'].keys()) != schema_props_keys:
++                raise ValueError(
++                    "Record does not match collection schema: %r != %r" % (
++                        record['properties'].keys(), 
++                        list(schema_props_keys) ))
++            if not validate_geometry_type(record):
++                raise ValueError(
++                    "Record's geometry type does not match "
++                    "collection schema's geometry type: %r != %r" % (
++                         record['geometry']['type'],
++                         collection.schema['geometry'] ))
++
++            cogr_feature = OGRFeatureBuilder().build(record, collection)
++            result = ograpi.OGR_L_CreateFeature(cogr_layer, cogr_feature)
++            if result != OGRERR_NONE:
++                raise RuntimeError("Failed to write record: %s" % record)
++            _deleteOgrFeature(cogr_feature)
++
++    def sync(self, collection):
++        """Syncs OGR to disk."""
++        cdef void *cogr_ds = self.cogr_ds
++        cdef void *cogr_layer = self.cogr_layer
++        if cogr_ds == NULL:
++            raise ValueError("Null data source")
++        log.debug("Syncing OGR to disk")
++
++        ograpi.GDALFlushCache(cogr_ds)
++
++
++cdef class Iterator:
++
++    """Provides iterated access to feature data.
++    """
++
++    # Reference to its Collection
++    cdef collection
++    cdef encoding
++    cdef int next_index
++    cdef stop
++    cdef start
++    cdef step
++    cdef fastindex
++    cdef stepsign
++
++    def __init__(self, collection, 
++            start=None, stop=None, step=None, bbox=None, mask=None):
++        if collection.session is None:
++            raise ValueError("I/O operation on closed collection")
++        self.collection = collection
++        cdef Session session
++        cdef void *cogr_geometry
++        session = self.collection.session
++        cdef void *cogr_layer = session.cogr_layer
++        if cogr_layer == NULL:
++            raise ValueError("Null layer")
++        ograpi.OGR_L_ResetReading(cogr_layer)
++        
++        if bbox and mask:
++            raise ValueError("mask and bbox can not be set together")
++        
++        if bbox:
++            ograpi.OGR_L_SetSpatialFilterRect(
++                cogr_layer, bbox[0], bbox[1], bbox[2], bbox[3])
++        elif mask:
++            cogr_geometry = OGRGeomBuilder().build(mask)
++            ograpi.OGR_L_SetSpatialFilter(cogr_layer, cogr_geometry)
++            ograpi.OGR_G_DestroyGeometry(cogr_geometry)
++            
++        else:
++            ograpi.OGR_L_SetSpatialFilter(
++                cogr_layer, NULL)
++        self.encoding = session.get_internalencoding()
++
++        self.fastindex = ograpi.OGR_L_TestCapability(
++            session.cogr_layer, OLC_FASTSETNEXTBYINDEX)
++
++        ftcount = ograpi.OGR_L_GetFeatureCount(session.cogr_layer, 0)
++        if ftcount == -1 and ((start is not None and start < 0) or
++                              (stop is not None and stop < 0)):
++            raise IndexError(
++                "collection's dataset does not support negative slice indexes")
++
++        if stop is not None and stop < 0:
++            stop += ftcount
++
++        if start is None:
++            start = 0
++        if start is not None and start < 0:
++            start += ftcount
++
++        # step size
++        if step is None:
++            step = 1
++        if step == 0:
++            raise ValueError("slice step cannot be zero")
++        if step < 0 and not self.fastindex:
++            warnings.warn("Layer does not support" \
++                    "OLCFastSetNextByIndex, negative step size may" \
++                    " be slow", RuntimeWarning)
++        self.stepsign = int(math.copysign(1, step))
++        self.stop = stop
++        self.start = start
++        self.step = step
++
++        self.next_index = start
++        log.debug("Index: %d", self.next_index)
++        ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++
++
++    def __iter__(self):
++        return self
++
++
++    def _next(self):
++        """Internal method to set read cursor to next item"""
++
++        cdef Session session
++        session = self.collection.session
++
++        # Check if next_index is valid
++        if self.next_index < 0:
++            raise StopIteration
++        
++        if self.stepsign == 1:
++            if self.next_index < self.start or (self.stop is not None and self.next_index >= self.stop):
++                raise StopIteration
++        else:
++            if self.next_index > self.start or (self.stop is not None and self.next_index <= self.stop):
++                raise StopIteration
++
++
++        # Set read cursor to next_item position
++        if self.step > 1 and self.fastindex:
++            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++
++        elif self.step > 1 and not self.fastindex and not self.next_index == self.start:
++            for _ in range(self.step - 1):
++                # TODO rbuffat add test -> OGR_L_GetNextFeature increments cursor by 1, therefore self.step - 1 as one increment was performed when feature is read
++                cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++                if cogr_feature == NULL:
++                    raise StopIteration
++        elif self.step > 1 and not self.fastindex and self.next_index == self.start:
++            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++
++        elif self.step == 0:
++            # ograpi.OGR_L_GetNextFeature increments read cursor by one
++            pass
++        elif self.step < 0:
++            ograpi.OGR_L_SetNextByIndex(session.cogr_layer, self.next_index)
++            
++        # set the next index
++        self.next_index += self.step
++
++
++    def __next__(self):
++        cdef void * cogr_feature
++        cdef Session session
++        session = self.collection.session
++
++        #Update read cursor
++        self._next()
++
++        # Get the next feature.
++        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++        if cogr_feature == NULL:
++            raise StopIteration
++
++        feature = FeatureBuilder().build(
++            cogr_feature,
++            bbox=False,
++            encoding=self.encoding,
++            driver=self.collection.driver
++        )
++        _deleteOgrFeature(cogr_feature)
++        return feature
++
++
++cdef class ItemsIterator(Iterator):
++
++    def __next__(self):
++
++        cdef long fid
++        cdef void * cogr_feature
++        cdef Session session
++        session = self.collection.session
++
++        #Update read cursor
++        self._next()
++
++        # Get the next feature.
++        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++        if cogr_feature == NULL:
++            raise StopIteration
++
++
++        fid = ograpi.OGR_F_GetFID(cogr_feature)
++        feature = FeatureBuilder().build(
++            cogr_feature,
++            bbox=False,
++            encoding=self.encoding,
++            driver=self.collection.driver
++        )
++        _deleteOgrFeature(cogr_feature)
++
++        return fid, feature
++
++
++cdef class KeysIterator(Iterator):
++
++    def __next__(self):
++        cdef long fid
++        cdef void * cogr_feature
++        cdef Session session
++        session = self.collection.session
++
++        #Update read cursor
++        self._next()
++
++        # Get the next feature.
++        cogr_feature = ograpi.OGR_L_GetNextFeature(session.cogr_layer)
++        if cogr_feature == NULL:
++            raise StopIteration
++
++        fid = ograpi.OGR_F_GetFID(cogr_feature)
++        _deleteOgrFeature(cogr_feature)
++
++        return fid
++
++
++def _listlayers(path):
++
++    """Provides a list of the layers in an OGR data source.
++    """
++    
++    cdef void *cogr_ds
++    cdef void *cogr_layer
++    cdef char *path_c
++    cdef char *name_c
++    
++    # Open OGR data source.
++    try:
++        path_b = path.encode('utf-8')
++    except UnicodeDecodeError:
++        path_b = path
++    path_c = path_b
++    with cpl_errs:
++        cogr_ds = ograpi.GDALOpenEx(path_c,
++             ograpi.GDAL_OF_VECTOR | ograpi.GDAL_OF_READONLY,
++             NULL,
++             NULL,
++             NULL)
++#         cogr_ds = ograpi.OGROpen(path_c, 0, NULL)
++    if cogr_ds == NULL:
++        raise ValueError("No data available at path '%s'" % path)
++    
++    # Loop over the layers to get their names.
++    layer_count = ograpi.GDALDatasetGetLayerCount(cogr_ds)
++    layer_names = []
++    for i in range(layer_count):
++        cogr_layer = ograpi.GDALDatasetGetLayer(cogr_ds, i)
++        name_c = ograpi.OGR_L_GetName(cogr_layer)
++        name_b = name_c
++        layer_names.append(name_b.decode('utf-8'))
++    
++    # Close up data source.
++    if cogr_ds is not NULL:
++        ograpi.GDALClose(cogr_ds)
++    cogr_ds = NULL
++
++    return layer_names
++
++def buffer_to_virtual_file(bytesbuf):
++    """Maps a bytes buffer to a virtual file.
++    """
++    vsi_filename = os.path.join('/vsimem', uuid.uuid4().hex)
++    vsi_cfilename = vsi_filename if not isinstance(vsi_filename, string_types) else vsi_filename.encode('utf-8')
++
++    vsi_handle = ograpi.VSIFileFromMemBuffer(vsi_cfilename, bytesbuf, len(bytesbuf), 0)
++    if vsi_handle == NULL:
++        raise OSError('failed to map buffer to file')
++    if ograpi.VSIFCloseL(vsi_handle) != 0:
++        raise OSError('failed to close mapped file handle')
++
++    return vsi_filename
++
++def remove_virtual_file(vsi_filename):
++    vsi_cfilename = vsi_filename if not isinstance(vsi_filename, string_types) else vsi_filename.encode('utf-8')
++    return ograpi.VSIUnlink(vsi_cfilename)
++
++
+--- a/setup.py
++++ b/setup.py
+@@ -72,11 +72,11 @@ include_dirs = []
+ library_dirs = []
+ libraries = []
+ extra_link_args = []
+-gdal_output = [None]*3
++gdal_output = [None]*4
+ 
+ try:
+     gdal_config = os.environ.get('GDAL_CONFIG', 'gdal-config')
+-    for i, flag in enumerate(("--cflags", "--libs", "--datadir")):
++    for i, flag in enumerate(("--cflags", "--libs", "--datadir", "--version")):
+         gdal_output[i] = check_output([gdal_config, flag]).strip()
+ 
+     for item in gdal_output[0].split():
+@@ -138,6 +138,16 @@ if os.path.exists("MANIFEST.in"):
+             "Cython.Build.cythonize not found. "
+             "Cython is required to build from a repo.")
+         sys.exit(1)
++
++    if gdal_output[3][0] == u'1':
++        log.info("Building Fiona for gdal 1.x: {}".format(gdal_output[3]))
++        shutil.copy('fiona/ogrext1.pyx', 'fiona/ogrext.pyx')
++        shutil.copy('fiona/ograpi1.pxd', 'fiona/ograpi.pxd')
++    else:
++        log.info("Building Fiona for gdal 2.x: {}".format(gdal_output[3]))
++        shutil.copy('fiona/ogrext2.pyx', 'fiona/ogrext.pyx')
++        shutil.copy('fiona/ograpi2.pxd', 'fiona/ograpi.pxd')
++
+     ext_modules = cythonize([
+         Extension('fiona._geometry', ['fiona/_geometry.pyx'], **ext_options),
+         Extension('fiona._transform', ['fiona/_transform.pyx'], **ext_options),
+--- a/requirements.txt
++++ b/requirements.txt
+@@ -2,3 +2,4 @@ argparse
+ cligj
+ six
+ ordereddict
++future
+--- /dev/null
++++ b/tests/test_bigint.py
+@@ -0,0 +1,69 @@
++import fiona
++import os
++import shutil
++import tempfile
++import unittest
++from fiona.ogrext import calc_gdal_version_num, get_gdal_version_num
++
++"""
++
++OGR 54bit handling: https://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
++
++Shapefile: OFTInteger fields are created by default with a width of 9
++characters, so to be unambiguously read as OFTInteger (and if specifying
++integer that require 10 or 11 characters. the field is dynamically extended
++like managed since a few versions). OFTInteger64 fields are created by default
++with a width of 18 digits, so to be unambiguously read as OFTInteger64, and
++extented to 19 or 20 if needed. Integer fields of width between 10 and 18
++will be read as OFTInteger64. Above they will be treated as OFTReal. In
++previous GDAL versions, Integer fields were created with a default with of 10,
++and thus will be now read as OFTInteger64. An open option, DETECT_TYPE=YES, can
++be specified so as OGR does a full scan of the DBF file to see if integer
++fields of size 10 or 11 hold 32 bit or 64 bit values and adjust the type
++accordingly (and same for integer fields of size 19 or 20, in case of overflow
++of 64 bit integer, OFTReal is chosen)
++"""
++class TestBigInt(unittest.TestCase):
++
++    def setUp(self):
++        self.tempdir = tempfile.mkdtemp()
++
++    def tearDown(self):
++        shutil.rmtree(self.tempdir)
++
++    def testCreateBigIntSchema(self):
++        name = os.path.join(self.tempdir, 'output1.shp')
++
++        a_bigint = 10 ** 18 - 1
++        fieldname = 'abigint'
++
++        kwargs = {
++            'driver': 'ESRI Shapefile',
++            'crs': 'EPSG:4326',
++            'schema': {
++                'geometry': 'Point',
++                'properties': [(fieldname, 'int:10')]}}
++        if get_gdal_version_num() < calc_gdal_version_num(2, 0, 0):
++            with self.assertRaises(OverflowError):
++                with fiona.open(name, 'w', **kwargs) as dst:
++                    rec = {}
++                    rec['geometry'] = {'type': 'Point', 'coordinates': (0, 0)}
++                    rec['properties'] = {fieldname: a_bigint}
++                    dst.write(rec)
++        else:
++
++            with fiona.open(name, 'w', **kwargs) as dst:
++                rec = {}
++                rec['geometry'] = {'type': 'Point', 'coordinates': (0, 0)}
++                rec['properties'] = {fieldname: a_bigint}
++                dst.write(rec)
++
++            with fiona.open(name) as src:
++                if get_gdal_version_num() >= calc_gdal_version_num(2, 0, 0):
++                    first = next(src)
++                    self.assertEqual(first['properties'][fieldname], a_bigint)
++
++
++if __name__ == "__main__":
++    # import sys;sys.argv = ['', 'Test.testName']
++    unittest.main()
+--- a/tests/test_props.py
++++ b/tests/test_props.py
+@@ -6,7 +6,7 @@ import tempfile
+ import fiona
+ from fiona import prop_type, prop_width
+ from fiona.rfc3339 import FionaDateType
+-
++from builtins import int
+ 
+ def test_width_str():
+     assert prop_width('str:254') == 254
+@@ -22,8 +22,8 @@ def test_width_other():
+ def test_types():
+     assert prop_type('str:254') == text_type
+     assert prop_type('str') == text_type
+-    assert prop_type('int') == type(0)
+-    assert prop_type('float') == type(0.0)
++    assert isinstance(0, prop_type('int'))
++    assert isinstance(0.0, prop_type('float'))
+     assert prop_type('date') == FionaDateType
+ 
+ 
diff --git a/debian/patches/series b/debian/patches/series
index 2c8106c..b07dc3d 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,3 @@
 0001-Rename-fio-command-to-fiona-to-avoid-name-clash.patch
 0002-Remove-outside-reference-possible-privacy-breach.patch
+0003-GDAL-2.0.patch

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



More information about the Pkg-grass-devel mailing list