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

Generated by: LCOV version 1.14