[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