From c2e360a7804cf8c3480fecfc0bac916c8ec63734 Mon Sep 17 00:00:00 2001
From: Luc Hermitte <luc.hermitte@c-s.fr>
Date: Tue, 17 Apr 2012 16:44:37 +0200
Subject: [PATCH] ENH: encapsulation of OGR (+loop on layer features)

---
 .../OGRAdapters/CMakeLists.txt                |   5 +-
 .../OGRAdapters/otbOGRDataSourceWrapper.cxx   |  62 ++++++++++
 .../OGRAdapters/otbOGRDataSourceWrapper.h     |  99 +++++++++++++--
 .../OGRAdapters/otbOGRDataSourceWrapper.txx   |   7 ++
 .../OGRAdapters/otbOGRFeatureWrapper.cxx      |  81 ++++++++++++
 .../OGRAdapters/otbOGRFeatureWrapper.h        |  80 ++++++++++++
 .../OGRAdapters/otbOGRLayerWrapper.cxx        |  78 +++++++++++-
 .../OGRAdapters/otbOGRLayerWrapper.h          | 115 +++++++++++++++---
 .../OGRAdapters/CMakeLists.txt                |  16 ++-
 .../OGRAdapters/otbOGRDataSourceWrapperIO.cxx |   5 +-
 .../otbOGRDataSourceWrapperNew.cxx            |   7 ++
 11 files changed, 514 insertions(+), 41 deletions(-)
 create mode 100644 Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.cxx
 create mode 100644 Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.h

diff --git a/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt b/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt
index 4ae9bf2e64..e14833d7f6 100644
--- a/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt
+++ b/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt
@@ -25,10 +25,11 @@ ENDIF(NOT OTB_INSTALL_NO_LIBRARIES)
 # Note: no txx allowed here
 IF(NOT OTB_INSTALL_NO_DEVELOPMENT)
   FILE(GLOB __files1 "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
-  # FILE(GLOB __files2 "${CMAKE_CURRENT_SOURCE_DIR}/*.txx")
+  FILE(GLOB __files2 "${CMAKE_CURRENT_SOURCE_DIR}/*.txx")
   # FILE(GLOB __files3 "${CMAKE_CURRENT_BINARY_DIR}/*.h")
   # INSTALL(FILES ${__files1} ${__files2} ${__files3}
-  INSTALL(FILES ${__files1}
+  # INSTALL(FILES ${__files1}
+  INSTALL(FILES ${__files1} ${__files2}
     DESTINATION ${OTB_INSTALL_INCLUDE_DIR_CM24}/UtilitiesAdapters/OGRAdapters
     COMPONENT Development)
 ENDIF(NOT OTB_INSTALL_NO_DEVELOPMENT)
diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx
index 73bd76797e..6203f876bc 100644
--- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx
+++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx
@@ -199,12 +199,57 @@ OGRLayer* otb::ogr::DataSource::GetLayerUnchecked(size_t i)
   return layer_ptr;
 }
 
+otb::ogr::Layer otb::ogr::DataSource::GetLayer(std::string const& name)
+{
+  assert(m_DataSource && "Datasource not initialized");
+  OGRLayer * layer_ptr = m_DataSource->GetLayerByName(name.c_str());
+  return otb::ogr::Layer(layer_ptr);
+}
+
+
+otb::ogr::Layer otb::ogr::DataSource::GetLayerChecked(std::string const& name)
+{
+  assert(m_DataSource && "Datasource not initialized");
+  OGRLayer * layer_ptr = m_DataSource->GetLayerByName(name.c_str());
+  if (!layer_ptr)
+    {
+    itkExceptionMacro( << "Cannot fetch any layer named <" << name
+      << "> in the OGRDataSource <" << m_DataSource->GetName() << ">.");
+    }
+  return otb::ogr::Layer(layer_ptr);
+}
+
 int otb::ogr::DataSource::GetLayersCount() const
 {
   assert(m_DataSource && "Datasource not initialized");
   return m_DataSource->GetLayerCount();
 }
 
+otb::ogr::Layer otb::ogr::DataSource::ExecuteSQL(
+  std::string const& statement, 
+  OGRGeometry * poSpatialFilter, 
+  char        const* pszDialect)
+{
+  assert(m_DataSource && "Datasource not initialized");
+  OGRLayer * layer_ptr = m_DataSource->ExecuteSQL(
+    statement.c_str(), poSpatialFilter, pszDialect);
+  if (!layer_ptr)
+    {
+#if defined(PREFER_EXCEPTION)
+    itkExceptionMacro( << "Unexpected error: cannot execute the SQL request <" << statement
+      << "> in the OGRDataSource <" << m_DataSource->GetName() << ">.");
+#else 
+    // Cannot use the deleter made for result sets obtained from
+    // OGRDataSource::ExecuteSQL because it checks for non-nullity....
+    // *sigh*
+    return otb::ogr::Layer(0);
+#endif
+    }
+  return otb::ogr::Layer(layer_ptr, m_DataSource);
+
+}
+
+
 /*===========================================================================*/
 /*===============================[ features ]================================*/
 /*===========================================================================*/
@@ -245,3 +290,20 @@ void otb::ogr::DataSource::PrintSelf(
   assert(! "Disabled to check if it makes sense...");
 }
 
+bool otb::ogr::DataSource::HasCapability(std::string const& capabilityName)
+{
+  assert(m_DataSource && "Datasource not initialized");
+  return m_DataSource->TestCapability(capabilityName.c_str());
+}
+
+void otb::ogr::DataSource::SyncToDisk()
+{
+  assert(m_DataSource && "Datasource not initialized");
+  const OGRErr res= m_DataSource->SyncToDisk();
+  if (res != OGRERR_NONE)
+    {
+    itkExceptionMacro( << "Cannot flush the pending of the OGRDataSource <"
+      << m_DataSource->GetName() << ">.");
+    }
+}
+
diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h
index 9aa2e6a2a0..f06e44e442 100644
--- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h
+++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h
@@ -32,6 +32,7 @@
 class OGRDataSource;
 class OGRLayer;
 class OGRSpatialReference;
+class OGRGeometry;
 #include "ogr_core.h" // OGRwkbGeometryType
 
 namespace otb { namespace ogr {
@@ -149,11 +150,16 @@ namespace otb { namespace ogr {
      * an encapsulation of OGR classes. In that particular case, it's an
      * encapsulation of \c OGRDataSource.
      *
-     * \note not meant to be inherited
-     * \note this class has an entity semantics: \em non-copyable, nor \em
+     * \note Not meant to be inherited
+     * \note This class has an entity semantics: \em non-copyable, nor \em
      * assignable.
      * \note \c OGRRegisterAll() is implicitly called on construction
-     * \internal as the class is not meant to be inherited, no new function is virtual.
+     * \internal As the class is not meant to be inherited, no new function is virtual.
+     *
+     * \note The following function haven't been encapsulated (yet?):
+     * - \c SetStyleTable() & \c GetStyleTable()
+     * - \c SetDriver() & \c GetDriver()
+     * - all functions related to the reference count.
      */
     class DataSource : public itk::DataObject
     {
@@ -281,9 +287,13 @@ namespace otb { namespace ogr {
     /**
      * Creates a new layer.
      * \param[in] name          name for the layer
-     * \param poSpatialRef      the coordinate system to use for the new layer, or NULL if no coordinate system is available.
-     * \param[in] eGType        the geometry type for the layer. Use wkbUnknown if there are no constraints on the types geometry to be written.
-     * \param[in] papszOptions  a StringList of name=value options. Options are driver specific.
+     * \param poSpatialRef      the coordinate system to use for the new layer,
+     *                          or NULL if no coordinate system is available.
+     * \param[in] eGType        the geometry type for the layer. Use wkbUnknown
+     *                          if there are no constraints on the types
+     *                          geometry to be written.
+     * \param[in] papszOptions  a StringList of name=value options. Options are
+     *                          driver specific.
      *
      * \return a proxy on the \c OGRLayer created.
      * \throw itk::ExceptionObject in case the layer cannot be created on the
@@ -353,7 +363,7 @@ namespace otb { namespace ogr {
     /**
      * Unchecked Accessor to a given layer.
      * \param[in] i  index of the layer to access
-     * \return a reference to the layer requested.
+     * \return the layer requested.
      * \pre <tt>i < GetLayersCount()</tt>, an assertion will abort the program
      * otherwise.
      * \pre the layer must available, an assertion will abort the program
@@ -362,11 +372,24 @@ namespace otb { namespace ogr {
      * \note Use \c GetLayerUnchecked() if invalid indices are programming
      * errors, or if null layers are to be expected.
      */
-    Layer GetLayer(size_t i);
-    /**\copydoc otb::ogr::DataSource::GetLayer()
+    Layer       GetLayer(size_t i);
+    /**\copydoc otb::ogr::DataSource::GetLayer(size_t)
      */
     Layer const GetLayer(size_t i) const;
 
+    /**
+     * Unchecked Accessor to a given layer.
+     * \param[in] name  name of the layer to search
+     * \return the layer requested, possibly a null one.
+     * \throw None
+     * \note Use \c GetLayerUnchecked(std::string const&) if you'd rather have
+     * an exception instead of testing whether the layer obtained is valid.
+     */
+    Layer       GetLayer(std::string const& name);
+    /**\copydoc otb::ogr::DataSource::GetLayer(std::string const&)
+     */
+    Layer const GetLayer(std::string const& name) const;
+
     /**
      * Checked Accessor to a given layer.
      * \param[in] i  index of the layer to access
@@ -381,6 +404,44 @@ namespace otb { namespace ogr {
     /**\copydoc otb::ogr::DataSource::GetLayerChecked()
      */
     Layer const GetLayerChecked(size_t i) const;
+
+    /**
+     * Checked Accessor to a given layer.
+     * \param[in] name  name of the layer to search
+     * \return the layer requested, possibly a null one.
+     * \throw itk::ExceptionObject if there exist no layer by that name
+     * \note use \c GetLayer(std::string const&) if you'd rather test the
+     * obtained layer instead of catching an exception.
+     */
+    Layer       GetLayerChecked(std::string const& name);
+    /**\copydoc otb::ogr::DataSource::GetLayerChecked(std::string const&)
+     */
+    Layer const GetLayerChecked(std::string const& name) const;
+
+    /**
+     * Excecutes the statement..
+     * \param[in] statement  textual description of the SQL statement.
+     * \param[in] poSpatialFilter  \c Geometry representing a spatial filter -- may be null.
+     * \param[in] pszDialect  allows control of the statement dialect. If set to
+     *                     NULL, the OGR SQL engine will be used, except for
+     *                     RDBMS drivers that will use their dedicated SQL
+     *                     engine, unless OGRSQL is explicitely passed as the
+     *                     dialect.
+     * \return a new \c Layer that contains the matching \c Features. In case of
+     * error, or no matching result sets, a \em null Layer will be returned.
+     * Check for \¢ Layer's validity before doing anything else.
+     * \throw None even when there is an error -- OGR can not report errors,
+     * neither this wrapping.
+     * \note the returned \c Layer will be automatically collected on its
+     * destruction ; i.e. unlike OGR API, no need to explicitly call \c
+     * OGRDataSource::ReleaseResultSet().
+     * \sa OGRDataSource::ExecuteSQL
+     */
+    Layer ExecuteSQL(
+      std::string const& statement,
+      OGRGeometry *  	 poSpatialFilter,
+      char        const* pszDialect);
+
     //@}
 
 
@@ -391,9 +452,25 @@ namespace otb { namespace ogr {
      * boolean expression to be used in \c if tests.
      * \see <em>Imperfect C++</em>, Matthew Wilson, Addisson-Welsey, par 24.6
      */
-    operator int boolean ::* () const {
+    operator int boolean ::* () const
+      {
       return m_DataSource ? &boolean::i : 0;
-    }
+      }
+
+    /**
+     * Flushes all changes to disk.
+     * \throw itd::ExceptionObject in case the flush operation failed.
+     * \sa OGRDataSource::SyncToDisk
+     */
+    void SyncToDisk();
+
+    /**
+     * Returns whether a capability is avalaible.
+     * \param[in] capabilityName  name of the capability to check.
+     * \throw None
+     * \sa OGRDataSource::TestCapability
+     */
+    bool HasCapability(std::string const& capabilityName);
 
     /** Access to raw \c OGRDataSource.
      * This function provides an abstraction leak in case deeper control on the
diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx
index 885aa79707..3a456ee029 100644
--- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx
+++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx
@@ -52,6 +52,13 @@ otb::ogr::Layer const otb::ogr::DataSource::GetLayer(size_t i) const
   return const_cast <DataSource*>(this)->GetLayer(i);
 }
 
+inline
+otb::ogr::Layer const otb::ogr::DataSource::GetLayer(std::string const& name) const
+{
+  return const_cast <DataSource*>(this)->GetLayer(name);
+}
+
+
 inline
 otb::ogr::Layer const otb::ogr::DataSource::GetLayerChecked(size_t i) const
 {
diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.cxx
new file mode 100644
index 0000000000..e8d10ad15b
--- /dev/null
+++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.cxx
@@ -0,0 +1,81 @@
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+/*===========================================================================*/
+/*===============================[ Includes ]================================*/
+/*===========================================================================*/
+#include "otbOGRFeatureWrapper.h"
+#include <boost/bind.hpp>
+#include <boost/make_shared.hpp>
+#include "ogr_feature.h"
+
+/*===========================================================================*/
+/*======================[ Construction / Destruction ]=======================*/
+/*===========================================================================*/
+otb::ogr::Feature::Feature(OGRFeatureDefn & definition)
+: m_Feature(
+  OGRFeature::CreateFeature(&definition),
+  boost::bind(&OGRFeature::DestroyFeature, _1))
+{
+  CheckInvariants();
+}
+
+otb::ogr::Feature::Feature(OGRFeature * feature)
+{
+  if (feature)
+    {
+    m_Feature.reset(feature, boost::bind(&OGRFeature::DestroyFeature, _1));
+    }
+  // else default is perfect -> delete null
+}
+
+otb::ogr::Feature::~Feature()
+{
+}
+
+otb::ogr::Feature otb::ogr::Feature::clone() const
+{
+  CheckInvariants();
+  const Feature res(m_Feature->Clone());
+  return res;
+}
+
+/*===========================================================================*/
+/*=================================[ Misc ]==================================*/
+/*===========================================================================*/
+void otb::ogr::Feature::PrintSelf(std::ostream & os, itk::Indent indent) const
+{
+  CheckInvariants();
+  os << indent << "+";
+  os << " " << m_Feature->GetFieldCount() << " fields\n";
+}
+
+bool otb::ogr::operator==(otb::ogr::Feature const& lhs, otb::ogr::Feature const& rhs)
+{
+  // special case: they may be null (end() mark)
+
+  // OGR is not const correct ...
+  OGRFeature * l = const_cast<OGRFeature*>(lhs.m_Feature.get());
+  OGRFeature * r = const_cast<OGRFeature*>(rhs.m_Feature.get());
+  return
+    (l == r ) // incl. ==0
+    || 
+    (l && r && l->Equal(r)) // must be non-null to compare them with Equal
+    ;
+}
+
diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.h
new file mode 100644
index 0000000000..8b84d43bbd
--- /dev/null
+++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.h
@@ -0,0 +1,80 @@
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __otbOGRFeatureWrapper_h
+#define __otbOGRFeatureWrapper_h
+
+// #include <iosfwd> // std::ostream&
+#include <cassert>
+#include <boost/shared_ptr.hpp>
+#include "itkIndent.h"
+
+class OGRFeature;
+class OGRGeometry;
+class OGRFeatureDefn;
+
+namespace otb {
+namespace ogr {
+class Feature;
+bool operator==(Feature const& lhs, Feature const& rhs);
+
+/**\ingroup Geometry
+ * \class Feature
+ * \invariant <tt>m_Feature != 0</tt>
+ */
+class Feature
+  {
+public:
+  // no default constructor
+  Feature(OGRFeatureDefn & definition);
+  Feature(OGRFeature * feature);
+  ~Feature();
+
+  Feature clone() const;
+  void PrintSelf(std::ostream &os, itk::Indent indent) const;
+
+  OGRFeature const& ogr() const
+    {
+    CheckInvariants();
+    return *m_Feature;
+    }
+  OGRFeature & ogr()
+    {
+    CheckInvariants();
+    return *m_Feature;
+    }
+
+  friend bool otb::ogr::operator==(Feature const& lhs, Feature const& rhs);
+private:
+  void CheckInvariants() const
+    {
+    assert(m_Feature && "OGRFeature can't be null");
+    }
+  boost::shared_ptr<OGRFeature> m_Feature;
+
+  };
+
+
+} // ogr namespace 
+} // otb namespace 
+
+
+#ifndef OTB_MANUAL_INSTANTIATION
+// #include "otbOGRFeatureWrapper.txx"
+#endif
+
+#endif // __otbOGRFeatureWrapper_h
diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx
index 8d65dde47d..002235436b 100644
--- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx
+++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx
@@ -22,12 +22,12 @@
 #include "otbOGRLayerWrapper.h"
 #include <cassert>
 #include <boost/bind.hpp>
+#include <boost/range/algorithm.hpp>
 #include "ogrsf_frmts.h" // OGRDataSource & OGRLayer
 
 /*===========================================================================*/
-/*==============================[ other stuff ]==============================*/
+/*======================[ Construction & Destruction ]=======================*/
 /*===========================================================================*/
-
 namespace  { // Anonymous namespace
   /**\ingroup Geometry
    * Deleter for \c boost::shared_ptr<> that doesn't delete.
@@ -53,12 +53,62 @@ otb::ogr::Layer::Layer(OGRLayer* layer, OGRDataSource* sourceInChargeOfLifeTime)
   // OGR always refuses "delete 0". *sigh*
 }
 
+/*===========================================================================*/
+/*===============================[ Features ]================================*/
+/*===========================================================================*/
 int otb::ogr::Layer::GetFeatureCount(bool doForceComputation) const
 {
   assert(m_Layer);
   return m_Layer->GetFeatureCount(doForceComputation);
 }
 
+otb::ogr::Feature otb::ogr::Layer::GetNextFeature()
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  return m_Layer->GetNextFeature();
+}
+
+otb::ogr::Layer::iterator otb::ogr::Layer::begin()
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  m_Layer->ResetReading();
+  return iterator(*this);
+}
+
+otb::ogr::Layer::const_iterator otb::ogr::Layer::cbegin() const
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  m_Layer->ResetReading();
+  return const_iterator(*const_cast <Layer*>(this));
+}
+
+void otb::ogr::Layer::CreateFeature(Feature feature)
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  m_Layer->CreateFeature(&feature.ogr());
+}
+
+void otb::ogr::Layer::DeleteFeature(long nFID)
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  m_Layer->DeleteFeature(nFID);
+}
+
+otb::ogr::Feature otb::ogr::Layer::GetFeature(long nFID)
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  Feature feat = m_Layer->GetFeature(nFID);
+}
+
+void otb::ogr::Layer::SetFeature(Feature feature)
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  m_Layer->SetFeature(&feature.ogr());
+}
+
+/*===========================================================================*/
+/*=================================[ Misc ]==================================*/
+/*===========================================================================*/
 std::string otb::ogr::Layer::GetName() const
 {
   assert(m_Layer && "null layer");
@@ -76,8 +126,10 @@ void otb::ogr::Layer::PrintSelf(std::ostream& os, itk::Indent indent) const
   os << indent << "+";
   if (m_Layer) // in case for odd reason the layer that should exist can't be found
     {
-    os << "Layer <" << m_Layer->GetName() << "\n";
-    // + for each feature
+    os << "Layer <" << m_Layer->GetName() << ">\n";
+    boost::for_each( // for each feature
+      *this,
+      boost::bind(&Feature::PrintSelf, _1, boost::ref(os), indent.GetNextIndent()));
     }
   else
     {
@@ -85,3 +137,21 @@ void otb::ogr::Layer::PrintSelf(std::ostream& os, itk::Indent indent) const
     }
 }
 
+/*===========================================================================*/
+/*============================[ Spatial Filter ]=============================*/
+/*===========================================================================*/
+
+OGRGeometry const* otb::ogr::Layer::GetSpatialFilter() const
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  OGRGeometry* spatialFilter = m_Layer->GetSpatialFilter();
+  return spatialFilter;
+}
+
+void otb::ogr::Layer::SetSpatialFilter(OGRGeometry const* spatialFilter)
+{
+  assert(m_Layer && "OGRLayer not initialized");
+  // const_cast because OGR is not 100% const-correct
+  m_Layer->SetSpatialFilter(const_cast <OGRGeometry*>(spatialFilter));
+}
+
diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h
index 25194448a3..da27e84931 100644
--- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h
+++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h
@@ -1,18 +1,18 @@
 /*=========================================================================
 
-  Program:   ORFEO Toolbox
-  Language:  C++
-  Date:      $Date$
-  Version:   $Revision$
+Program:   ORFEO Toolbox
+Language:  C++
+Date:      $Date$
+Version:   $Revision$
 
 
-  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
-  See OTBCopyright.txt for details.
+Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+See OTBCopyright.txt for details.
 
 
-     This software is distributed WITHOUT ANY WARRANTY; without even
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-     PURPOSE.  See the above copyright notices for more information.
+This software is distributed WITHOUT ANY WARRANTY; without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.  See the above copyright notices for more information.
 
 =========================================================================*/
 #ifndef __otbLayer_h
@@ -20,14 +20,19 @@
 
 // #include <iosfwd> // std::ostream&
 #include <boost/shared_ptr.hpp>
+// #include <boost/iterator/iterator_adaptor.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/utility/enable_if.hpp>
 #include "itkIndent.h"
-class OGRLayer; // fwd declaration
+#include "otbOGRFeatureWrapper.h"
+class OGRLayer; // fwd declarations
 class OGRDataSource;
+class OGRGeometry;
 
-namespace otb { namespace ogr
-{
+namespace otb { namespace ogr {
 /**\ingroup Geometry
- * \brief Layer of geometric objets.
+ * \class Layer
+ * \brief %Layer of geometric objets.
  *
  * It provides an encapsulation of OGR classes. In that particular case, it's an
  * encapsulation of \c OGRLayer.
@@ -43,7 +48,7 @@ namespace otb { namespace ogr
  * \todo find a way to tell whether the related \c OGRDataSource was released
  */
 class Layer
-// : public itk::DataObject
+  // : public itk::DataObject
   {
 public:
   /**\name Standard class typedefs */
@@ -65,6 +70,9 @@ public:
   explicit Layer(OGRLayer* layer);
   Layer(OGRLayer* layer, OGRDataSource* sourceInChargeOfLifeTime);
   //@}
+
+  /**\name Features collection */
+  //@{
   /** Returns the number of elements in the layer.
    * \param[in] doForceCompuation  indicates whether the size shall be computed
    * even so it's expensive to do so.
@@ -75,12 +83,22 @@ public:
    */
   int GetFeatureCount(bool doForceComputation) const;
 
+  void CreateFeature(Feature feature);
+  void DeleteFeature(long nFID);
+  Feature GetFeature(long nFID);
+  void SetFeature(Feature feature);
+  //@}
+
+  /** Returns the name given to the layer, if any.
+  */
   std::string GetName() const;
 
   /** Prints self into stream. */
   void PrintSelf(std::ostream& os, itk::Indent indent) const;
 
 
+  /**\copydoc operator int boolean ::* () const
+  */
   struct boolean{ int i; };
   /** Can the layer be used (ie not null).
    *
@@ -88,9 +106,10 @@ public:
    * boolean expression to be used in \c if tests.
    * @see <em>Imperfect C++</em>, Matthew Wilson, Addisson-Welsey, par 24.6
    */
-  operator int boolean ::* () const {
+  operator int boolean ::* () const
+    {
     return m_Layer ? &boolean::i : 0;
-  }
+    }
 
   /** Access to raw \c OGRLayer.
    * This function provides an abstraction leak in case deeper control on the
@@ -102,10 +121,72 @@ public:
    */
   OGRLayer & ogr();
 
+  /**\name Spatial filter property
+   * \internal the I/O geometry is an undeletable pointer, can be may be null.
+   * \todo we'll see later if a Geometry capsule is defined, or a
+   * \c nondeletable<> pointer type.
+   */
+  //@{
+  OGRGeometry const* GetSpatialFilter() const;
+  void SetSpatialFilter(OGRGeometry const* spatialFilter);
+  //@}
+
+  /**\name Iteration */
+  //@{
+  template <class Value> class feature_iter
+    : public boost::iterator_facade<feature_iter<Value>, Value, boost::single_pass_traversal_tag>
+    {
+    struct enabler {};
+  public:
+    feature_iter()
+      : m_Layer(0), m_Crt(0) {}
+    explicit feature_iter(otb::ogr::Layer & layer)
+      : m_Layer(&layer), m_Crt(layer.GetNextFeature()) {}
+    template <class OtherValue> feature_iter(
+      feature_iter<OtherValue> const& other,
+      typename boost::enable_if<boost::is_convertible<OtherValue*,Value*>
+      , enabler
+      >::type = enabler()
+    )
+      : m_Layer(other.m_Layer), m_Crt(other.m_Crt)
+      {}
+  private:
+    friend class boost::iterator_core_access;
+    template <class> friend class feature_iter;
+
+    template <class OtherValue> bool equal(feature_iter<OtherValue> const& other) const
+      { return other.m_Crt == m_Crt; }
+    void increment()
+      { 
+      assert(m_Layer && "cannot increment end()");
+      m_Crt = m_Layer->GetNextFeature();
+      }
+    Value & dereference() const 
+      { return m_Crt; }
+
+    otb::ogr::Layer * m_Layer;
+    otb::ogr::Feature m_Crt;
+    };
+
+  template <class> friend class feature_iter;
+  typedef feature_iter<Feature      > iterator;
+  typedef feature_iter<Feature const> const_iterator;
+
+  const_iterator begin() const { return cbegin(); }
+  const_iterator end  () const { return cend  (); }
+  const_iterator cbegin() const ;
+  const_iterator cend() const { return iterator(); }
+  iterator       begin() ;
+  iterator       end() { return iterator(); }
+  //@}
 private:
+  Feature GetNextFeature();
 
   /** Data implementation.
-   * \internal The actual %layer implementation belongs to the \c otb::Layer object.
+   * \internal
+   * The actual %layer implementation belongs to the \c otb::Layer object,
+   * unless this is the result of \c ExecuteSQL. In that case a deleter is set
+   * to correctly release the layer.
    */
   boost::shared_ptr<OGRLayer> m_Layer;
   };
diff --git a/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt b/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt
index 0546c835c6..b89c1032c0 100644
--- a/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt
+++ b/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt
@@ -4,7 +4,10 @@ SET(OGR_TESTS ${CXX_TEST_PATH}/otbOGRTests)
 
 SET(OGRCommon_SRC
 otbOGRDataSourceWrapperNew.cxx
-# otbOGRDataSourceWrapperIO.cxx
+)
+
+SET(OGRNon_UT_SRC
+otbOGRDataSourceWrapperIO.cxx
 )
 
 find_package(Boost COMPONENTS filesystem unit_test_framework)
@@ -22,7 +25,6 @@ ENDIF(Boost_FOUND)
 
 IF (Boost_UNIT_TEST_FRAMEWORK_FOUND)
   OTB_ADD_EXECUTABLE(otbOGRTests "${OGRCommon_SRC}" "OTBIO;OTBTesting")
-  # TARGET_LINK_LIBRARIES(otbOGRTests OTBOGRAdapters  OTBTesting itkvcl)
   TARGET_LINK_LIBRARIES(otbOGRTests OTBOGRAdapters OTBTesting
     ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
     )
@@ -33,8 +35,12 @@ IF (Boost_UNIT_TEST_FRAMEWORK_FOUND)
     otbOGRDataSourceWrapperNew
     )
 ENDIF(Boost_UNIT_TEST_FRAMEWORK_FOUND)
-# ADD_TEST(coTuOGRDataSourceWrapperIO ${OGR_TESTS}
-  # otbOGRDataSourceWrapperIO
-# )
+
+OTB_ADD_EXECUTABLE(otbOGRTestsV "${OGRNon_UT_SRC}" "OTBIO;OTBTesting")
+TARGET_LINK_LIBRARIES(otbOGRTestsV OTBOGRAdapters OTBTesting
+  )
+ADD_TEST(coTuOGRDataSourceWrapperIO ${OGR_TESTS_NON_UT}
+  otbOGRDataSourceWrapperIO
+  )
 
 ENDIF( NOT OTB_DISABLE_CXX_TESTING AND BUILD_TESTING )
diff --git a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx
index 49d26d45f2..a9aa4d2b96 100644
--- a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx
+++ b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx
@@ -29,8 +29,8 @@ using namespace otb;
 /*===========================================================================*/
 /*==============================[ other stuff ]==============================*/
 /*===========================================================================*/
-int otbOGRDataSourceNew (int argc, char **argv)
-// int main(int argc, char **argv)
+// int otbOGRDataSourceNew (int argc, char **argv)
+int main(int argc, char **argv)
 {
   if (argc <1)
     {
@@ -43,5 +43,6 @@ int otbOGRDataSourceNew (int argc, char **argv)
   std::cout << "nb layers:\t" << ds->GetLayersCount() << std::endl;
   std::cout << "nb features(0):\t" << ds->Size(false) << std::endl;
   std::cout << "nb features(1):\t" << ds->Size(true) << std::endl;
+  ds->Print(std::cout);
   return EXIT_SUCCESS;
 }
diff --git a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx
index 3e3f1786ff..976a420ca8 100644
--- a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx
+++ b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx
@@ -64,6 +64,12 @@ BOOST_AUTO_TEST_CASE(OGRDataSource_mem_add_n_del_layer)
   BOOST_CHECK_THROW(ds->GetLayerChecked(1), itk::ExceptionObject);
   BOOST_CHECK_EQUAL(l.GetName(), k_one);
   BOOST_CHECK_EQUAL(l0.GetName(), k_one);
+  BOOST_CHECK_EQUAL(l0.GetName(), k_one);
+
+  BOOST_CHECK_EQUAL(ds->GetLayer(k_one).GetName(), k_one);
+  BOOST_CHECK_EQUAL(ds->GetLayerChecked(k_one).GetName(), k_one);
+  BOOST_ASSERT(! ds->GetLayer(k_two));
+  BOOST_CHECK_THROW(ds->GetLayerChecked(k_two), itk::ExceptionObject);
 
   ogr::Layer l2 = ds -> CreateLayer(k_two);
   BOOST_CHECK_EQUAL(ds->GetLayersCount(), 2);
@@ -71,6 +77,7 @@ BOOST_AUTO_TEST_CASE(OGRDataSource_mem_add_n_del_layer)
   BOOST_CHECK_EQUAL(ds->Size(true), 0);
   BOOST_CHECK_EQUAL(ds->GetLayer(0).GetName(), k_one);
   BOOST_CHECK_EQUAL(ds->GetLayer(1).GetName(), k_two);
+  BOOST_CHECK_EQUAL(ds->GetLayer(k_two).GetName(), k_two);
   BOOST_CHECK_THROW(ds->GetLayerChecked(2), itk::ExceptionObject);
 
   ds->DeleteLayer(0);
-- 
GitLab