Skip to content

File WkbWriter.h

File List > detail > io > WkbWriter.h

Go to the documentation of this file

// Copyright (c) 2023-2023, Oslandia.
// SPDX-License-Identifier: LGPL-2.0-or-later

#ifndef _SFCGAL_IO_WKBWRITER_H_
#define _SFCGAL_IO_WKBWRITER_H_

#include <boost/endian/conversion.hpp>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <vector>

#include "SFCGAL/Geometry.h"
#include "SFCGAL/config.h"

using srid_t = uint32_t;

namespace SFCGAL::detail::io {

class SFCGAL_API WkbWriter {
public:
  WkbWriter(std::ostream &s, bool asHexString = false)
      : _s(s), _asHexString(asHexString){};

  void
  write(const Geometry      &g,
        boost::endian::order wkbOrder = boost::endian::order::native);

  void
  write(const Geometry &g, const srid_t &srid,
        boost::endian::order wkbOrder = boost::endian::order::native);

private:
  void
  writeGeometryType(const Geometry &g, boost::endian::order wkbOrder =
                                           boost::endian::order::native);

  void
  writeInner(const Point         &g,
             boost::endian::order wkbOrder = boost::endian::order::native);

  void
  writeInner(const LineString    &g,
             boost::endian::order wkbOrder = boost::endian::order::native);
  void
  writeInnerRing(const LineString    &g,
                 boost::endian::order wkbOrder = boost::endian::order::native);

  void
  writeInner(const Polygon       &g,
             boost::endian::order wkbOrder = boost::endian::order::native);

  void
  writeInner(const GeometryCollection &g,
             boost::endian::order      wkbOrder = boost::endian::order::native);

  template <typename M, typename G>
  void
  writeInner(const M &g, boost::endian::order wkbOrder);

  void
  writeInner(const Triangle      &g,
             boost::endian::order wkbOrder = boost::endian::order::native);

  void
  writeCoordinate(const Point         &g,
                  boost::endian::order wkbOrder = boost::endian::order::native);

  void
  writeRec(const Geometry      &g,
           boost::endian::order wkbOrder = boost::endian::order::native);

  std::ostream &_s;

  bool _asHexString;

  template <std::size_t N>
  auto
  toStream(const std::array<std::byte, N> &arr) -> void
  {
    if (_asHexString) {
      for (const std::byte &byteVal : arr) {
        _s << _prefix << std::hex << std::setw(2) << std::setfill('0')
           << static_cast<int>(byteVal);
      }
    } else {
      for (const std::byte &byteVal : arr) {
        _s << static_cast<unsigned char>(byteVal);
      }
    }
  }

  template <typename T>
  auto
  toByte(const T x, boost::endian::order byteOrder) -> void
  {
    T y = x;
    if (boost::endian::order::native != byteOrder) {
      boost::endian::endian_reverse_inplace(y);
    }
    toStream(*reinterpret_cast<std::array<std::byte, sizeof(T)> *>(&y));
  }

  srid_t _srid;

  bool        _useSrid = false;
  bool        _isEWKB  = false;
  std::string _prefix;
};

} // namespace SFCGAL::detail::io

#endif