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