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  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "ogrsf_frmts.h"
30 #include "ogr_p.h"
31 
32 #include "geometryreader.h"
33 #include "cplerrors.h"
34 #include "ogr_flatgeobuf.h"
35 
36 using namespace flatbuffers;
37 using namespace FlatGeobuf;
38 using namespace ogr_flatgeobuf;
39 
CPLErrorInvalidLength(const char * message)40 static std::nullptr_t CPLErrorInvalidLength(const char *message) {
41     CPLError(CE_Failure, CPLE_AppDefined, "Invalid length detected: %s", message);
42     return nullptr;
43 }
44 
readPoint()45 OGRPoint *GeometryReader::readPoint()
46 {
47     const auto xy = m_geometry->xy();
48     if (xy == nullptr)
49         return CPLErrorInvalidPointer("XY data");
50     const auto offsetXy = m_offset * 2;
51     const auto aXy = xy->data();
52     if (offsetXy >= xy->size())
53         return CPLErrorInvalidLength("XY data");
54     if (m_hasZ) {
55         const auto z = m_geometry->z();
56         if (z == nullptr)
57             return CPLErrorInvalidPointer("Z data");
58         if (m_offset >= z->size())
59             return CPLErrorInvalidLength("Z data");
60         const auto aZ = z->data();
61         if (m_hasM) {
62             const auto pM = m_geometry->m();
63             if (pM == nullptr)
64                 return CPLErrorInvalidPointer("M data");
65             if (m_offset >= pM->size())
66                 return CPLErrorInvalidLength("M data");
67             const auto aM = pM->data();
68             return new OGRPoint { EndianScalar(aXy[offsetXy + 0]),
69                                   EndianScalar(aXy[offsetXy + 1]),
70                                   EndianScalar(aZ[m_offset]),
71                                   EndianScalar(aM[m_offset]) };
72         } else {
73             return new OGRPoint { EndianScalar(aXy[offsetXy + 0]),
74                                   EndianScalar(aXy[offsetXy + 1]),
75                                   EndianScalar(aZ[m_offset]) };
76         }
77     } else if (m_hasM) {
78         const auto pM = m_geometry->m();
79         if (pM == nullptr)
80             return CPLErrorInvalidPointer("M data");
81         if (m_offset >= pM->size())
82             return CPLErrorInvalidLength("M data");
83         const auto aM = pM->data();
84         return OGRPoint::createXYM( EndianScalar(aXy[offsetXy + 0]),
85                                     EndianScalar(aXy[offsetXy + 1]),
86                                     EndianScalar(aM[m_offset]) );
87     } else {
88         return new OGRPoint { EndianScalar(aXy[offsetXy + 0]),
89                               EndianScalar(aXy[offsetXy + 1]) };
90     }
91 }
92 
readMultiPoint()93 OGRMultiPoint *GeometryReader::readMultiPoint()
94 {
95     m_length = m_length / 2;
96     if (m_length >= feature_max_buffer_size)
97         return CPLErrorInvalidLength("MultiPoint");
98     auto mp = std::unique_ptr<OGRMultiPoint>(new OGRMultiPoint());
99     for (uint32_t i = 0; i < m_length; i++) {
100         m_offset = i;
101         const auto p = readPoint();
102         if (p == nullptr)
103             return nullptr;
104         mp->addGeometryDirectly(p);
105     }
106     return mp.release();
107 }
108 
readMultiLineString()109 OGRMultiLineString *GeometryReader::readMultiLineString()
110 {
111     const auto pEnds = m_geometry->ends();
112     if (pEnds == nullptr)
113         return CPLErrorInvalidPointer("MultiLineString ends data");
114     auto mls = std::unique_ptr<OGRMultiLineString>(new OGRMultiLineString());
115     m_offset = 0;
116     for (uint32_t i = 0; i < pEnds->size(); i++) {
117         const auto e = pEnds->Get(i);
118         if (e < m_offset)
119             return CPLErrorInvalidLength("MultiLineString");
120         m_length = e - m_offset;
121         const auto ls = readSimpleCurve<OGRLineString>();
122         if (ls == nullptr)
123             return nullptr;
124         mls->addGeometryDirectly(ls);
125         m_offset = e;
126     }
127     return mls.release();
128 }
129 
readSimpleCurve(OGRSimpleCurve * sc)130 OGRErr GeometryReader::readSimpleCurve(OGRSimpleCurve *sc)
131 {
132     if (m_offset > feature_max_buffer_size || m_length > feature_max_buffer_size - m_offset)
133         return CPLErrorInvalidSize("curve offset max");
134     const uint32_t offsetLen = m_length + m_offset;
135     auto xy = m_geometry->xy();
136     if (xy == nullptr) {
137         CPLErrorInvalidPointer("XY data");
138         return OGRERR_CORRUPT_DATA;
139     }
140     if (offsetLen > xy->size() / 2)
141         return CPLErrorInvalidSize("curve XY offset");
142     const auto aXy = xy->data();
143     const auto ogrXY = reinterpret_cast<const OGRRawPoint *>(aXy) + m_offset;
144     if (m_hasZ) {
145         const auto pZ = m_geometry->z();
146         if (pZ == nullptr) {
147             CPLErrorInvalidPointer("Z data");
148             return OGRERR_CORRUPT_DATA;
149         }
150         if (offsetLen > pZ->size())
151             return CPLErrorInvalidSize("curve Z offset");
152         const auto aZ = pZ->data();
153         if (m_hasM) {
154             const auto pM = m_geometry->m();
155             if (pM == nullptr) {
156                 CPLErrorInvalidPointer("M data");
157                 return OGRERR_CORRUPT_DATA;
158             }
159             if (offsetLen > pM->size())
160                 return CPLErrorInvalidSize("curve M offset");
161             const auto aM = pM->data();
162 #if CPL_IS_LSB
163             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,
169                              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         } else {
176 #if CPL_IS_LSB
177             sc->setPoints(m_length, ogrXY, aZ + m_offset);
178 #else
179             sc->setNumPoints(m_length, false);
180             for( uint32_t i = 0; i < m_length; i++ )
181             {
182                 sc->setPoint(i,
183                              EndianScalar(ogrXY[i].x),
184                              EndianScalar(ogrXY[i].y),
185                              EndianScalar(aZ[m_offset + i]));
186             }
187 #endif
188         }
189     } else if (m_hasM) {
190         const auto pM = m_geometry->m();
191         if (pM == nullptr) {
192             CPLErrorInvalidPointer("M data");
193             return OGRERR_CORRUPT_DATA;
194         }
195         if (offsetLen > pM->size())
196             return CPLErrorInvalidSize("curve M offset");
197         const auto aM = pM->data();
198 #if CPL_IS_LSB
199         sc->setPointsM(m_length, ogrXY, aM + m_offset);
200 #else
201         sc->setNumPoints(m_length, false);
202         for( uint32_t i = 0; i < m_length; i++ )
203         {
204             sc->setPointM(i,
205                             EndianScalar(ogrXY[i].x),
206                             EndianScalar(ogrXY[i].y),
207                             EndianScalar(aM[m_offset + i]));
208         }
209 #endif
210     } else {
211 #if CPL_IS_LSB
212         sc->setPoints(m_length, ogrXY);
213 #else
214         sc->setNumPoints(m_length, false);
215         for( uint32_t i = 0; i < m_length; i++ )
216         {
217             sc->setPoint(i,
218                          EndianScalar(ogrXY[i].x),
219                          EndianScalar(ogrXY[i].y));
220         }
221 #endif
222     }
223     return OGRERR_NONE;
224 }
225 
readPolygon()226 OGRPolygon *GeometryReader::readPolygon()
227 {
228     const auto ends = m_geometry->ends();
229     auto p = std::unique_ptr<OGRPolygon>(new OGRPolygon());
230     if (ends == nullptr || ends->size() < 2) {
231         m_length = m_length / 2;
232         const auto lr = readSimpleCurve<OGRLinearRing>();
233         if (lr == nullptr)
234             return nullptr;
235         p->addRingDirectly(lr);
236     } else {
237         for (uint32_t i = 0; i < ends->size(); i++) {
238             const auto e = ends->Get(i);
239             if (e < m_offset)
240                 return CPLErrorInvalidLength("Polygon");
241             m_length = e - m_offset;
242             const auto lr = readSimpleCurve<OGRLinearRing>();
243             m_offset = e;
244             if (lr == nullptr)
245                 continue;
246             p->addRingDirectly(lr);
247         }
248         if (p->IsEmpty())
249             return nullptr;
250     }
251     return p.release();
252 }
253 
readMultiPolygon()254 OGRMultiPolygon *GeometryReader::readMultiPolygon()
255 {
256     auto parts = m_geometry->parts();
257     if (parts == nullptr)
258         return CPLErrorInvalidPointer("parts data");
259     auto mp = std::unique_ptr<OGRMultiPolygon>(new OGRMultiPolygon());
260     for (uoffset_t i = 0; i < parts->size(); i++) {
261         GeometryReader reader { parts->Get(i), GeometryType::Polygon, m_hasZ, m_hasM };
262         auto g = std::unique_ptr<OGRGeometry>(reader.read());
263         if (g == nullptr)
264             return nullptr;
265         mp->addGeometryDirectly(g.release()->toPolygon());
266     }
267     return mp.release();
268 }
269 
readGeometryCollection()270 OGRGeometryCollection *GeometryReader::readGeometryCollection()
271 {
272     auto parts = m_geometry->parts();
273     if (parts == nullptr)
274         return CPLErrorInvalidPointer("parts data");
275     auto gc = std::unique_ptr<OGRGeometryCollection>(new OGRGeometryCollection());
276     for (uoffset_t i = 0; i < parts->size(); i++) {
277         GeometryReader reader { parts->Get(i), m_hasZ, m_hasM };
278         auto g = std::unique_ptr<OGRGeometry>(reader.read());
279         if (g == nullptr)
280             return nullptr;
281         gc->addGeometryDirectly(g.release());
282     }
283     return gc.release();
284 }
285 
readCompoundCurve()286 OGRCompoundCurve *GeometryReader::readCompoundCurve()
287 {
288     auto parts = m_geometry->parts();
289     if (parts == nullptr)
290         return CPLErrorInvalidPointer("parts data");
291     auto cc = std::unique_ptr<OGRCompoundCurve>(new OGRCompoundCurve());
292     for (uoffset_t i = 0; i < parts->size(); i++) {
293         GeometryReader reader { parts->Get(i), m_hasZ, m_hasM };
294         auto g = std::unique_ptr<OGRGeometry>(reader.read());
295         if (dynamic_cast<OGRCurve *>(g.get()) == nullptr)
296             return nullptr;
297         auto poCurve = g.release()->toCurve();
298         if( cc->addCurveDirectly(poCurve) != OGRERR_NONE )
299         {
300             delete poCurve;
301             return nullptr;
302         }
303     }
304     return cc.release();
305 }
306 
readCurvePolygon()307 OGRCurvePolygon *GeometryReader::readCurvePolygon()
308 {
309     auto parts = m_geometry->parts();
310     if (parts == nullptr)
311         return CPLErrorInvalidPointer("parts data");
312     auto cp = std::unique_ptr<OGRCurvePolygon>(new OGRCurvePolygon());
313     for (uoffset_t i = 0; i < parts->size(); i++) {
314         GeometryReader reader { parts->Get(i), m_hasZ, m_hasM };
315         auto g = std::unique_ptr<OGRGeometry>(reader.read());
316         if (dynamic_cast<OGRCurve *>(g.get()) == nullptr)
317             return nullptr;
318         auto poCurve = g.release()->toCurve();
319         if( cp->addRingDirectly(poCurve) != OGRERR_NONE )
320         {
321             delete poCurve;
322             return nullptr;
323         }
324     }
325     return cp.release();
326 }
327 
readMultiCurve()328 OGRMultiCurve *GeometryReader::readMultiCurve()
329 {
330     auto parts = m_geometry->parts();
331     if (parts == nullptr)
332         return CPLErrorInvalidPointer("parts data");
333     auto mc = std::unique_ptr<OGRMultiCurve>(new OGRMultiCurve());
334     for (uoffset_t i = 0; i < parts->size(); i++) {
335         GeometryReader reader { parts->Get(i), m_hasZ, m_hasM };
336         auto g = std::unique_ptr<OGRGeometry>(reader.read());
337         if (dynamic_cast<OGRCurve *>(g.get()) == nullptr)
338             return nullptr;
339         mc->addGeometryDirectly(g.release());
340     }
341     return mc.release();
342 }
343 
readMultiSurface()344 OGRMultiSurface *GeometryReader::readMultiSurface()
345 {
346     auto parts = m_geometry->parts();
347     if (parts == nullptr)
348         return CPLErrorInvalidPointer("parts data");
349     auto ms = std::unique_ptr<OGRMultiSurface>(new OGRMultiSurface());
350     for (uoffset_t i = 0; i < parts->size(); i++) {
351         GeometryReader reader { parts->Get(i), m_hasZ, m_hasM };
352         auto g = std::unique_ptr<OGRGeometry>(reader.read());
353         if (dynamic_cast<OGRSurface *>(g.get()) == nullptr)
354             return nullptr;
355         auto poSubGeom = g.release();
356         if( ms->addGeometryDirectly(poSubGeom) != OGRERR_NONE )
357         {
358             delete poSubGeom;
359             return nullptr;
360         }
361     }
362     return ms.release();
363 }
364 
readPolyhedralSurface()365 OGRPolyhedralSurface *GeometryReader::readPolyhedralSurface()
366 {
367     auto parts = m_geometry->parts();
368     if (parts == nullptr)
369         return CPLErrorInvalidPointer("parts data");
370     auto ps = std::unique_ptr<OGRPolyhedralSurface>(new OGRPolyhedralSurface());
371     for (uoffset_t i = 0; i < parts->size(); i++) {
372         GeometryReader reader { parts->Get(i), m_hasZ, m_hasM };
373         auto g = std::unique_ptr<OGRGeometry>(reader.read());
374         if (g == nullptr )
375             return nullptr;
376         auto poSubGeom = g.release();
377         if( ps->addGeometryDirectly(poSubGeom) != OGRERR_NONE )
378         {
379             delete poSubGeom;
380             return nullptr;
381         }
382     }
383     return ps.release();
384 }
385 
readTIN()386 OGRTriangulatedSurface *GeometryReader::readTIN()
387 {
388     const auto ends = m_geometry->ends();
389     auto ts = std::unique_ptr<OGRTriangulatedSurface>(new OGRTriangulatedSurface());
390     if (ends == nullptr || ends->size() < 2) {
391         m_length = m_length / 2;
392         if (m_length != 4)
393             return CPLErrorInvalidLength("TIN");
394         const auto lr = readSimpleCurve<OGRLinearRing>();
395         if (lr == nullptr)
396             return nullptr;
397         auto t = new OGRTriangle();
398         t->addRingDirectly(lr);
399         ts->addGeometryDirectly(t);
400     } else {
401         for (uint32_t i = 0; i < ends->size(); i++) {
402             const auto e = ends->Get(i);
403             if (e < m_offset)
404                 return CPLErrorInvalidLength("TIN");
405             m_length = e - m_offset;
406             if (m_length != 4)
407                 return CPLErrorInvalidLength("TIN");
408             const auto lr = readSimpleCurve<OGRLinearRing>();
409             m_offset = e;
410             if (lr == nullptr)
411                 continue;
412             auto t = new OGRTriangle();
413             t->addRingDirectly(lr);
414             ts->addGeometryDirectly(t);
415         }
416         if (ts->IsEmpty())
417             return nullptr;
418     }
419     return ts.release();
420 }
421 
readTriangle()422 OGRTriangle *GeometryReader::readTriangle()
423 {
424     m_length = m_length / 2;
425     if (m_length != 4)
426         return CPLErrorInvalidLength("readTriangle");
427     auto lr = readSimpleCurve<OGRLinearRing>();
428     if (lr == nullptr)
429         return nullptr;
430     auto t = new OGRTriangle();
431     t->addRingDirectly(lr);
432     return t;
433 }
434 
read()435 OGRGeometry *GeometryReader::read()
436 {
437     // nested types
438     switch (m_geometryType) {
439         case GeometryType::GeometryCollection: return readGeometryCollection();
440         case GeometryType::MultiPolygon: return readMultiPolygon();
441         case GeometryType::CompoundCurve: return readCompoundCurve();
442         case GeometryType::CurvePolygon: return readCurvePolygon();
443         case GeometryType::MultiCurve: return readMultiCurve();
444         case GeometryType::MultiSurface: return readMultiSurface();
445         case GeometryType::PolyhedralSurface: return readPolyhedralSurface();
446         default: break;
447     }
448 
449     // if not nested must have geometry data
450     const auto pXy = m_geometry->xy();
451     if (pXy == nullptr)
452         return CPLErrorInvalidPointer("XY data");
453     if (m_hasZ && m_geometry->z() == nullptr)
454         return CPLErrorInvalidPointer("Z data");
455     if (m_hasM && m_geometry->m() == nullptr)
456         return CPLErrorInvalidPointer("M data");
457     const auto xySize = pXy->size();
458     if (xySize >= (feature_max_buffer_size / sizeof(OGRRawPoint)))
459         return CPLErrorInvalidLength("XY data");
460     m_length = xySize;
461 
462     switch (m_geometryType) {
463         case GeometryType::Point: return readPoint();
464         case GeometryType::MultiPoint: return readMultiPoint();
465         case GeometryType::LineString: return readSimpleCurve<OGRLineString>(true);
466         case GeometryType::MultiLineString: return readMultiLineString();
467         case GeometryType::Polygon: return readPolygon();
468         case GeometryType::CircularString: return readSimpleCurve<OGRCircularString>(true);
469         case GeometryType::Triangle: return readTriangle();
470         case GeometryType::TIN: return readTIN();
471         default:
472             CPLError(CE_Failure, CPLE_AppDefined, "GeometryReader::read: Unknown type %d", (int) m_geometryType);
473     }
474     return nullptr;
475 }
476