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