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