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 : }