File WkbReader.h
File List > detail > io > WkbReader.h
Go to the documentation of this file
// Copyright (c) 2023-2023, Oslandia.
// SPDX-License-Identifier: LGPL-2.0-or-later
#ifndef SFCGAL_IO_WKBREADER_H_
#define SFCGAL_IO_WKBREADER_H_
#include <sstream>
#include "SFCGAL/config.h"
#include "SFCGAL/Geometry.h"
#include "SFCGAL/GeometryCollection.h"
#include "SFCGAL/LineString.h"
#include "SFCGAL/MultiLineString.h"
#include "SFCGAL/MultiPoint.h"
#include "SFCGAL/MultiPolygon.h"
#include "SFCGAL/Point.h"
#include "SFCGAL/Polygon.h"
#include "SFCGAL/PolyhedralSurface.h"
#include "SFCGAL/PreparedGeometry.h"
#include "SFCGAL/Triangle.h"
#include "SFCGAL/TriangulatedSurface.h"
#include "SFCGAL/detail/tools/InputStreamReader.h"
#include <boost/endian/conversion.hpp> // don't use bit, since it requires c++20
//
namespace SFCGAL::detail::io {
class SFCGAL_API WkbReader {
public:
WkbReader(std::istream &wkbString, bool asHexString = false)
: _reader(wkbString), _asHexString(asHexString)
{
}
auto
readWkb() -> void
{
// wkbOrder
std::byte wkbOrder{read<std::byte>()};
_swapEndian =
boost::endian::order::native == boost::endian::order(wkbOrder);
_geometry = readGeometry();
}
auto
geometry() -> std::unique_ptr<SFCGAL::Geometry>
{
return std::move(_geometry);
}
auto
preparedGeometry() -> std::unique_ptr<SFCGAL::PreparedGeometry>
{
return std::make_unique<SFCGAL::PreparedGeometry>(std::move(_geometry),
_srid);
}
[[nodiscard]] auto
srid() const -> srid_t
{
return _srid;
}
private:
template <typename T>
auto
read() -> T
{
const size_t sizeType = sizeof(T);
union {
std::array<std::byte, sizeType> byteArray;
T d;
};
if (_asHexString) {
const size_t nbElements = 2;
const size_t totalBytesToRead = nbElements * sizeType;
std::string buffer(totalBytesToRead, '\0');
_reader.readBytes(buffer, totalBytesToRead);
const int base = 16;
for (size_t i = 0; i < sizeType; i++) {
size_t chunkPos = nbElements * i;
std::string byteStr = buffer.substr(chunkPos, nbElements);
byteArray[i] =
static_cast<std::byte>(std::stoi(byteStr, nullptr, base));
}
_index += sizeType * nbElements;
} else {
std::string buffer(sizeType, '\0');
_reader.readBytes(buffer, sizeType);
std::transform(buffer.begin(), buffer.end(), byteArray.begin(),
[](char c) { return std::byte(c); });
_index += sizeType;
}
return d;
}
auto
readGeometry() -> std::unique_ptr<SFCGAL::Geometry>
{
GeometryType geometryType = readGeometryType();
return readGeometryData(geometryType);
}
auto
readGeometryType() -> GeometryType
{
auto geometryType = read<uint32_t>();
if (_isEWKB || ((geometryType & wkbSRID) == wkbSRID)) {
if (!_isEWKB) {
readSRID();
_isEWKB = true;
}
if ((geometryType & wkbZ) == wkbZ) {
_is3D = true;
}
if ((geometryType & wkbM) == wkbM) {
_isMeasured = true;
}
geometryType &= 0x0FFFFFFF;
} else {
if (geometryType >= COORDINATE_XYZM) {
_is3D = true;
_isMeasured = true;
geometryType -= COORDINATE_XYZM;
} else if (geometryType >= COORDINATE_XYM) {
_is3D = false;
_isMeasured = true;
geometryType -= COORDINATE_XYM;
} else if (geometryType >= COORDINATE_XYZ) {
_is3D = true;
_isMeasured = false;
geometryType -= COORDINATE_XYZ;
}
}
return static_cast<GeometryType>(geometryType);
}
auto
readGeometryData(GeometryType geometryType) -> std::unique_ptr<Geometry>
{
switch (geometryType) {
case TYPE_POINT:
return std::unique_ptr<SFCGAL::Geometry>{readInnerPoint().clone()};
case TYPE_LINESTRING:
return std::unique_ptr<SFCGAL::Geometry>(readInnerLineString().clone());
case TYPE_POLYGON:
return std::unique_ptr<SFCGAL::Geometry>(readInnerPolygon().clone());
case TYPE_GEOMETRYCOLLECTION:
return std::unique_ptr<SFCGAL::Geometry>(
readInnerGeometryCollection().clone());
case TYPE_MULTIPOINT:
return std::unique_ptr<SFCGAL::Geometry>(
readInnerMultiGeometries<MultiPoint, Point>().clone());
case TYPE_MULTILINESTRING:
return std::unique_ptr<SFCGAL::Geometry>(
readInnerMultiGeometries<MultiLineString, LineString>().clone());
case TYPE_MULTIPOLYGON:
return std::unique_ptr<SFCGAL::Geometry>(
readInnerMultiGeometries<MultiPolygon, Polygon>().clone());
case TYPE_TRIANGLE:
return std::unique_ptr<SFCGAL::Geometry>(readInnerTriangle().clone());
case TYPE_TRIANGULATEDSURFACE:
return std::unique_ptr<SFCGAL::Geometry>(
readInnerTriangulatedSurface().clone());
case TYPE_POLYHEDRALSURFACE:
return std::unique_ptr<SFCGAL::Geometry>(
readInnerPolyhedralSurface().clone());
default:
std::ostringstream oss;
oss << "WkbWriter: type '" << geometryType << "' is not supported";
std::cerr << oss.str() << std::endl;
return {};
}
}
auto
readSRID() -> void
{
_srid = read<uint32_t>();
}
auto
readInnerPoint() -> Point;
auto
readInnerLineString() -> LineString;
auto
readInnerPolygon() -> Polygon;
template <typename M, typename G>
auto
readInnerMultiGeometries() -> M;
auto
readInnerTriangle() -> Triangle;
auto
readInnerGeometryCollection() -> GeometryCollection;
auto
readInnerTriangulatedSurface() -> TriangulatedSurface;
auto
readInnerPolyhedralSurface() -> PolyhedralSurface;
bool _is3D = false;
bool _isMeasured = false;
tools::InputStreamReader _reader;
bool _asHexString;
bool _swapEndian = false;
std::streamoff _index = 0;
srid_t _srid = 0;
bool _isEWKB = false;
std::unique_ptr<SFCGAL::Geometry> _geometry;
};
} // namespace SFCGAL::detail::io
#endif