LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/flatgeobuf - geometryreader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 253 313 80.8 %
Date: 2024-11-21 22:18:42 Functions: 15 16 93.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  FlatGeobuf driver
       4             :  * Purpose:  Implements GeometryReader class.
       5             :  * Author:   Björn Harrtell <bjorn at wololo dot org>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2018-2019, Björn Harrtell <bjorn at wololo dot org>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogrsf_frmts.h"
      14             : #include "ogr_p.h"
      15             : 
      16             : #include "geometryreader.h"
      17             : #include "cplerrors.h"
      18             : #include "ogr_flatgeobuf.h"
      19             : 
      20             : using namespace flatbuffers;
      21             : using namespace FlatGeobuf;
      22             : using namespace ogr_flatgeobuf;
      23             : 
      24           0 : static std::nullptr_t CPLErrorInvalidLength(const char *message)
      25             : {
      26           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Invalid length detected: %s",
      27             :              message);
      28           0 :     return nullptr;
      29             : }
      30             : 
      31         243 : OGRPoint *GeometryReader::readPoint()
      32             : {
      33         243 :     const auto offsetXy = m_offset * 2;
      34         243 :     if (offsetXy >= m_length)
      35           0 :         return CPLErrorInvalidLength("XY data");
      36         243 :     if (m_hasZ)
      37             :     {
      38          22 :         const auto z = m_geometry->z();
      39          22 :         if (z == nullptr)
      40           0 :             return CPLErrorInvalidPointer("Z data");
      41          22 :         if (m_offset >= z->size())
      42           0 :             return CPLErrorInvalidLength("Z data");
      43          22 :         const auto aZ = z->data();
      44          22 :         if (m_hasM)
      45             :         {
      46          11 :             const auto pM = m_geometry->m();
      47          11 :             if (pM == nullptr)
      48           0 :                 return CPLErrorInvalidPointer("M data");
      49          11 :             if (m_offset >= pM->size())
      50           0 :                 return CPLErrorInvalidLength("M data");
      51          11 :             const auto aM = pM->data();
      52          11 :             return new OGRPoint{EndianScalar(m_xy[offsetXy + 0]),
      53          11 :                                 EndianScalar(m_xy[offsetXy + 1]),
      54          11 :                                 EndianScalar(aZ[m_offset]),
      55          11 :                                 EndianScalar(aM[m_offset])};
      56             :         }
      57             :         else
      58             :         {
      59          11 :             return new OGRPoint{EndianScalar(m_xy[offsetXy + 0]),
      60          11 :                                 EndianScalar(m_xy[offsetXy + 1]),
      61          11 :                                 EndianScalar(aZ[m_offset])};
      62             :         }
      63             :     }
      64         221 :     else if (m_hasM)
      65             :     {
      66          11 :         const auto pM = m_geometry->m();
      67          11 :         if (pM == nullptr)
      68           0 :             return CPLErrorInvalidPointer("M data");
      69          11 :         if (m_offset >= pM->size())
      70           0 :             return CPLErrorInvalidLength("M data");
      71          11 :         const auto aM = pM->data();
      72          11 :         return OGRPoint::createXYM(EndianScalar(m_xy[offsetXy + 0]),
      73          11 :                                    EndianScalar(m_xy[offsetXy + 1]),
      74          22 :                                    EndianScalar(aM[m_offset]));
      75             :     }
      76             :     else
      77             :     {
      78         210 :         return new OGRPoint{EndianScalar(m_xy[offsetXy + 0]),
      79         210 :                             EndianScalar(m_xy[offsetXy + 1])};
      80             :     }
      81             : }
      82             : 
      83          11 : OGRMultiPoint *GeometryReader::readMultiPoint()
      84             : {
      85          11 :     auto length = m_length / 2;
      86          11 :     if (length >= feature_max_buffer_size)
      87           0 :         return CPLErrorInvalidLength("MultiPoint");
      88          22 :     auto mp = std::make_unique<OGRMultiPoint>();
      89          40 :     for (uint32_t i = 0; i < length; i++)
      90             :     {
      91          29 :         m_offset = i;
      92          29 :         const auto p = readPoint();
      93          29 :         if (p == nullptr)
      94           0 :             return nullptr;
      95          29 :         mp->addGeometryDirectly(p);
      96             :     }
      97          11 :     return mp.release();
      98             : }
      99             : 
     100          16 : OGRMultiLineString *GeometryReader::readMultiLineString()
     101             : {
     102          16 :     const auto ends = m_geometry->ends();
     103          32 :     auto mls = std::make_unique<OGRMultiLineString>();
     104          16 :     if (ends == nullptr || ends->size() < 2)
     105             :     {
     106           6 :         m_length = m_length / 2;
     107           6 :         const auto part = readSimpleCurve<OGRLineString>();
     108           6 :         if (part == nullptr)
     109           0 :             return nullptr;
     110           6 :         mls->addGeometryDirectly(part);
     111             :     }
     112             :     else
     113             :     {
     114          10 :         m_offset = 0;
     115          34 :         for (uint32_t i = 0; i < ends->size(); i++)
     116             :         {
     117          24 :             const auto e = ends->Get(i);
     118          24 :             if (e < m_offset)
     119           0 :                 return CPLErrorInvalidLength("MultiLineString");
     120          24 :             m_length = e - m_offset;
     121          24 :             const auto ls = readSimpleCurve<OGRLineString>();
     122          24 :             if (ls == nullptr)
     123           0 :                 return nullptr;
     124          24 :             mls->addGeometryDirectly(ls);
     125          24 :             m_offset = e;
     126             :         }
     127             :     }
     128          16 :     return mls.release();
     129             : }
     130             : 
     131         551 : OGRErr GeometryReader::readSimpleCurve(OGRSimpleCurve *sc)
     132             : {
     133         551 :     if (m_offset > feature_max_buffer_size ||
     134         551 :         m_length > feature_max_buffer_size - m_offset)
     135           0 :         return CPLErrorInvalidSize("curve offset max");
     136         551 :     const uint32_t offsetLen = m_length + m_offset;
     137         551 :     if (offsetLen > m_xylength / 2)
     138           0 :         return CPLErrorInvalidSize("curve XY offset");
     139         551 :     const auto ogrXY = reinterpret_cast<const OGRRawPoint *>(m_xy) + m_offset;
     140         551 :     if (m_hasZ)
     141             :     {
     142          67 :         const auto pZ = m_geometry->z();
     143          67 :         if (pZ == nullptr)
     144             :         {
     145           0 :             CPLErrorInvalidPointer("Z data");
     146           0 :             return OGRERR_CORRUPT_DATA;
     147             :         }
     148          67 :         if (offsetLen > pZ->size())
     149           0 :             return CPLErrorInvalidSize("curve Z offset");
     150          67 :         const auto aZ = pZ->data();
     151          67 :         if (m_hasM)
     152             :         {
     153          29 :             const auto pM = m_geometry->m();
     154          29 :             if (pM == nullptr)
     155             :             {
     156           0 :                 CPLErrorInvalidPointer("M data");
     157           0 :                 return OGRERR_CORRUPT_DATA;
     158             :             }
     159          29 :             if (offsetLen > pM->size())
     160           0 :                 return CPLErrorInvalidSize("curve M offset");
     161          29 :             const auto aM = pM->data();
     162             : #if CPL_IS_LSB
     163          29 :             sc->setPoints(m_length, ogrXY, aZ + m_offset, aM + m_offset);
     164             : #else
     165             :             sc->setNumPoints(m_length, false);
     166             :             for (uint32_t i = 0; i < m_length; i++)
     167             :             {
     168             :                 sc->setPoint(i, EndianScalar(ogrXY[i].x),
     169             :                              EndianScalar(ogrXY[i].y),
     170             :                              EndianScalar(aZ[m_offset + i]),
     171             :                              EndianScalar(aM[m_offset + i]));
     172             :             }
     173             : #endif
     174             :         }
     175             :         else
     176             :         {
     177             : #if CPL_IS_LSB
     178          38 :             sc->setPoints(m_length, ogrXY, aZ + m_offset);
     179             : #else
     180             :             sc->setNumPoints(m_length, false);
     181             :             for (uint32_t i = 0; i < m_length; i++)
     182             :             {
     183             :                 sc->setPoint(i, EndianScalar(ogrXY[i].x),
     184             :                              EndianScalar(ogrXY[i].y),
     185             :                              EndianScalar(aZ[m_offset + i]));
     186             :             }
     187             : #endif
     188             :         }
     189             :     }
     190         484 :     else if (m_hasM)
     191             :     {
     192          29 :         const auto pM = m_geometry->m();
     193          29 :         if (pM == nullptr)
     194             :         {
     195           0 :             CPLErrorInvalidPointer("M data");
     196           0 :             return OGRERR_CORRUPT_DATA;
     197             :         }
     198          29 :         if (offsetLen > pM->size())
     199           0 :             return CPLErrorInvalidSize("curve M offset");
     200          29 :         const auto aM = pM->data();
     201             : #if CPL_IS_LSB
     202          29 :         sc->setPointsM(m_length, ogrXY, aM + m_offset);
     203             : #else
     204             :         sc->setNumPoints(m_length, false);
     205             :         for (uint32_t i = 0; i < m_length; i++)
     206             :         {
     207             :             sc->setPointM(i, EndianScalar(ogrXY[i].x), EndianScalar(ogrXY[i].y),
     208             :                           EndianScalar(aM[m_offset + i]));
     209             :         }
     210             : #endif
     211             :     }
     212             :     else
     213             :     {
     214             : #if CPL_IS_LSB
     215         455 :         sc->setPoints(m_length, ogrXY);
     216             : #else
     217             :         sc->setNumPoints(m_length, false);
     218             :         for (uint32_t i = 0; i < m_length; i++)
     219             :         {
     220             :             sc->setPoint(i, EndianScalar(ogrXY[i].x), EndianScalar(ogrXY[i].y));
     221             :         }
     222             : #endif
     223             :     }
     224         551 :     return OGRERR_NONE;
     225             : }
     226             : 
     227         443 : OGRPolygon *GeometryReader::readPolygon()
     228             : {
     229         443 :     const auto ends = m_geometry->ends();
     230         886 :     auto p = std::make_unique<OGRPolygon>();
     231         443 :     if (ends == nullptr || ends->size() < 2)
     232             :     {
     233         427 :         m_length = m_length / 2;
     234         427 :         const auto lr = readSimpleCurve<OGRLinearRing>();
     235         427 :         if (lr == nullptr)
     236           0 :             return nullptr;
     237         427 :         p->addRingDirectly(lr);
     238             :     }
     239             :     else
     240             :     {
     241          48 :         for (uint32_t i = 0; i < ends->size(); i++)
     242             :         {
     243          32 :             const auto e = ends->Get(i);
     244          32 :             if (e < m_offset)
     245           0 :                 return CPLErrorInvalidLength("Polygon");
     246          32 :             m_length = e - m_offset;
     247          32 :             const auto lr = readSimpleCurve<OGRLinearRing>();
     248          32 :             m_offset = e;
     249          32 :             if (lr == nullptr)
     250           0 :                 continue;
     251          32 :             p->addRingDirectly(lr);
     252             :         }
     253          16 :         if (p->IsEmpty())
     254           0 :             return nullptr;
     255             :     }
     256         443 :     return p.release();
     257             : }
     258             : 
     259          24 : OGRMultiPolygon *GeometryReader::readMultiPolygon()
     260             : {
     261          24 :     auto parts = m_geometry->parts();
     262          24 :     if (parts == nullptr)
     263           0 :         return CPLErrorInvalidPointer("parts data");
     264          48 :     auto mp = std::make_unique<OGRMultiPolygon>();
     265          68 :     for (uoffset_t i = 0; i < parts->size(); i++)
     266             :     {
     267             :         auto g = std::unique_ptr<OGRGeometry>(
     268          44 :             readPart(parts->Get(i), GeometryType::Polygon));
     269          44 :         if (g == nullptr)
     270           0 :             return nullptr;
     271          44 :         mp->addGeometryDirectly(g.release()->toPolygon());
     272             :     }
     273          24 :     return mp.release();
     274             : }
     275             : 
     276          13 : OGRGeometryCollection *GeometryReader::readGeometryCollection()
     277             : {
     278          13 :     auto parts = m_geometry->parts();
     279          13 :     if (parts == nullptr)
     280           0 :         return CPLErrorInvalidPointer("parts data");
     281          26 :     auto gc = std::make_unique<OGRGeometryCollection>();
     282          38 :     for (uoffset_t i = 0; i < parts->size(); i++)
     283             :     {
     284          25 :         auto g = std::unique_ptr<OGRGeometry>(readPart(parts->Get(i)));
     285          25 :         if (g == nullptr)
     286           0 :             return nullptr;
     287          25 :         gc->addGeometryDirectly(g.release());
     288             :     }
     289          13 :     return gc.release();
     290             : }
     291             : 
     292           5 : OGRCompoundCurve *GeometryReader::readCompoundCurve()
     293             : {
     294           5 :     auto parts = m_geometry->parts();
     295           5 :     if (parts == nullptr)
     296           0 :         return CPLErrorInvalidPointer("parts data");
     297          10 :     auto cc = std::make_unique<OGRCompoundCurve>();
     298          14 :     for (uoffset_t i = 0; i < parts->size(); i++)
     299             :     {
     300          10 :         auto g = std::unique_ptr<OGRGeometry>(readPart(parts->Get(i)));
     301          10 :         if (dynamic_cast<OGRCurve *>(g.get()) == nullptr)
     302           0 :             return nullptr;
     303          10 :         auto poCurve = g.release()->toCurve();
     304          10 :         if (cc->addCurveDirectly(poCurve) != OGRERR_NONE)
     305             :         {
     306           1 :             delete poCurve;
     307           1 :             return nullptr;
     308             :         }
     309             :     }
     310           4 :     return cc.release();
     311             : }
     312             : 
     313          10 : OGRCurvePolygon *GeometryReader::readCurvePolygon()
     314             : {
     315          10 :     auto parts = m_geometry->parts();
     316          10 :     if (parts == nullptr)
     317           0 :         return CPLErrorInvalidPointer("parts data");
     318          20 :     auto cp = std::make_unique<OGRCurvePolygon>();
     319          26 :     for (uoffset_t i = 0; i < parts->size(); i++)
     320             :     {
     321          17 :         auto g = std::unique_ptr<OGRGeometry>(readPart(parts->Get(i)));
     322          17 :         if (dynamic_cast<OGRCurve *>(g.get()) == nullptr)
     323           0 :             return nullptr;
     324          17 :         auto poCurve = g.release()->toCurve();
     325          17 :         if (cp->addRingDirectly(poCurve) != OGRERR_NONE)
     326             :         {
     327           1 :             delete poCurve;
     328           1 :             return nullptr;
     329             :         }
     330             :     }
     331           9 :     return cp.release();
     332             : }
     333             : 
     334           4 : OGRMultiCurve *GeometryReader::readMultiCurve()
     335             : {
     336           4 :     auto parts = m_geometry->parts();
     337           4 :     if (parts == nullptr)
     338           0 :         return CPLErrorInvalidPointer("parts data");
     339           8 :     auto mc = std::make_unique<OGRMultiCurve>();
     340          12 :     for (uoffset_t i = 0; i < parts->size(); i++)
     341             :     {
     342           8 :         auto g = std::unique_ptr<OGRGeometry>(readPart(parts->Get(i)));
     343           8 :         if (dynamic_cast<OGRCurve *>(g.get()) == nullptr)
     344           0 :             return nullptr;
     345           8 :         mc->addGeometryDirectly(g.release());
     346             :     }
     347           4 :     return mc.release();
     348             : }
     349             : 
     350           5 : OGRMultiSurface *GeometryReader::readMultiSurface()
     351             : {
     352           5 :     auto parts = m_geometry->parts();
     353           5 :     if (parts == nullptr)
     354           0 :         return CPLErrorInvalidPointer("parts data");
     355          10 :     auto ms = std::make_unique<OGRMultiSurface>();
     356          13 :     for (uoffset_t i = 0; i < parts->size(); i++)
     357             :     {
     358           9 :         auto g = std::unique_ptr<OGRGeometry>(readPart(parts->Get(i)));
     359           9 :         if (dynamic_cast<OGRSurface *>(g.get()) == nullptr)
     360           0 :             return nullptr;
     361           9 :         auto poSubGeom = g.release();
     362           9 :         if (ms->addGeometryDirectly(poSubGeom) != OGRERR_NONE)
     363             :         {
     364           1 :             delete poSubGeom;
     365           1 :             return nullptr;
     366             :         }
     367             :     }
     368           4 :     return ms.release();
     369             : }
     370             : 
     371           3 : OGRPolyhedralSurface *GeometryReader::readPolyhedralSurface()
     372             : {
     373           3 :     auto parts = m_geometry->parts();
     374           3 :     if (parts == nullptr)
     375           0 :         return CPLErrorInvalidPointer("parts data");
     376           6 :     auto ps = std::make_unique<OGRPolyhedralSurface>();
     377           9 :     for (uoffset_t i = 0; i < parts->size(); i++)
     378             :     {
     379           7 :         auto g = std::unique_ptr<OGRGeometry>(readPart(parts->Get(i)));
     380           7 :         if (g == nullptr)
     381           0 :             return nullptr;
     382           7 :         auto poSubGeom = g.release();
     383           7 :         if (ps->addGeometryDirectly(poSubGeom) != OGRERR_NONE)
     384             :         {
     385           1 :             delete poSubGeom;
     386           1 :             return nullptr;
     387             :         }
     388             :     }
     389           2 :     return ps.release();
     390             : }
     391             : 
     392           2 : OGRTriangulatedSurface *GeometryReader::readTIN()
     393             : {
     394           2 :     const auto ends = m_geometry->ends();
     395           4 :     auto ts = std::make_unique<OGRTriangulatedSurface>();
     396           2 :     if (ends == nullptr || ends->size() < 2)
     397             :     {
     398           1 :         m_length = m_length / 2;
     399           1 :         if (m_length != 4)
     400           0 :             return CPLErrorInvalidLength("TIN");
     401           1 :         const auto lr = readSimpleCurve<OGRLinearRing>();
     402           1 :         if (lr == nullptr)
     403           0 :             return nullptr;
     404           1 :         auto t = new OGRTriangle();
     405           1 :         t->addRingDirectly(lr);
     406           1 :         ts->addGeometryDirectly(t);
     407             :     }
     408             :     else
     409             :     {
     410           3 :         for (uint32_t i = 0; i < ends->size(); i++)
     411             :         {
     412           2 :             const auto e = ends->Get(i);
     413           2 :             if (e < m_offset)
     414           0 :                 return CPLErrorInvalidLength("TIN");
     415           2 :             m_length = e - m_offset;
     416           2 :             if (m_length != 4)
     417           0 :                 return CPLErrorInvalidLength("TIN");
     418           2 :             const auto lr = readSimpleCurve<OGRLinearRing>();
     419           2 :             m_offset = e;
     420           2 :             if (lr == nullptr)
     421           0 :                 continue;
     422           2 :             auto t = new OGRTriangle();
     423           2 :             t->addRingDirectly(lr);
     424           2 :             ts->addGeometryDirectly(t);
     425             :         }
     426           1 :         if (ts->IsEmpty())
     427           0 :             return nullptr;
     428             :     }
     429           2 :     return ts.release();
     430             : }
     431             : 
     432           1 : OGRTriangle *GeometryReader::readTriangle()
     433             : {
     434           1 :     m_length = m_length / 2;
     435           1 :     if (m_length != 4)
     436           0 :         return CPLErrorInvalidLength("readTriangle");
     437           1 :     auto lr = readSimpleCurve<OGRLinearRing>();
     438           1 :     if (lr == nullptr)
     439           0 :         return nullptr;
     440           1 :     auto t = new OGRTriangle();
     441           1 :     t->addRingDirectly(lr);
     442           1 :     return t;
     443             : }
     444             : 
     445         809 : OGRGeometry *GeometryReader::read()
     446             : {
     447             :     // nested types
     448         809 :     switch (m_geometryType)
     449             :     {
     450          13 :         case GeometryType::GeometryCollection:
     451          13 :             return readGeometryCollection();
     452          24 :         case GeometryType::MultiPolygon:
     453          24 :             return readMultiPolygon();
     454           5 :         case GeometryType::CompoundCurve:
     455           5 :             return readCompoundCurve();
     456          10 :         case GeometryType::CurvePolygon:
     457          10 :             return readCurvePolygon();
     458           4 :         case GeometryType::MultiCurve:
     459           4 :             return readMultiCurve();
     460           5 :         case GeometryType::MultiSurface:
     461           5 :             return readMultiSurface();
     462           3 :         case GeometryType::PolyhedralSurface:
     463           3 :             return readPolyhedralSurface();
     464         745 :         default:
     465         745 :             break;
     466             :     }
     467             : 
     468             :     // if not nested must have geometry data
     469         745 :     const auto pXy = m_geometry->xy();
     470         745 :     if (pXy == nullptr)
     471           0 :         return CPLErrorInvalidPointer("XY data");
     472         745 :     if (m_hasZ && m_geometry->z() == nullptr)
     473           0 :         return CPLErrorInvalidPointer("Z data");
     474         745 :     if (m_hasM && m_geometry->m() == nullptr)
     475           0 :         return CPLErrorInvalidPointer("M data");
     476         745 :     const auto xySize = pXy->size();
     477         745 :     if (xySize >= (feature_max_buffer_size / sizeof(OGRRawPoint)))
     478           0 :         return CPLErrorInvalidLength("XY data");
     479         745 :     m_length = xySize;
     480         745 :     m_xylength = m_length;
     481         745 :     m_xy = pXy->data();
     482             : 
     483         745 :     switch (m_geometryType)
     484             :     {
     485         214 :         case GeometryType::Point:
     486         214 :             return readPoint();
     487          11 :         case GeometryType::MultiPoint:
     488          11 :             return readMultiPoint();
     489          38 :         case GeometryType::LineString:
     490          38 :             return readSimpleCurve<OGRLineString>(true);
     491          16 :         case GeometryType::MultiLineString:
     492          16 :             return readMultiLineString();
     493         443 :         case GeometryType::Polygon:
     494         443 :             return readPolygon();
     495          20 :         case GeometryType::CircularString:
     496          20 :             return readSimpleCurve<OGRCircularString>(true);
     497           1 :         case GeometryType::Triangle:
     498           1 :             return readTriangle();
     499           2 :         case GeometryType::TIN:
     500           2 :             return readTIN();
     501           0 :         default:
     502           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     503             :                      "GeometryReader::read: Unknown type %d",
     504           0 :                      (int)m_geometryType);
     505             :     }
     506           0 :     return nullptr;
     507             : }

Generated by: LCOV version 1.14