Skip to content

Commit

Permalink
Merge branch 'feat/binary_wkb' into 'master'
Browse files Browse the repository at this point in the history
Feat/binary wkb

See merge request sfcgal/SFCGAL!306
  • Loading branch information
lbartoletti committed Jun 3, 2024
2 parents 6e0504c + 7af4b05 commit 6c98e75
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 63 deletions.
4 changes: 2 additions & 2 deletions src/Geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ auto
Geometry::asWkb(boost::endian::order wkbOrder, bool asHex) const -> std::string
{
std::ostringstream oss;
detail::io::WkbWriter writer(oss);
writer.write(*this, wkbOrder, asHex);
detail::io::WkbWriter writer(oss, asHex);
writer.write(*this, wkbOrder);
return oss.str();
}
///
Expand Down
4 changes: 2 additions & 2 deletions src/PreparedGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ PreparedGeometry::asEWKB(boost::endian::order wkbOrder, bool asHex) const
-> std::string
{
std::ostringstream oss;
detail::io::WkbWriter writer(oss);
writer.write(*_geometry, _srid, wkbOrder, asHex);
detail::io::WkbWriter writer(oss, asHex);
writer.write(*_geometry, _srid, wkbOrder);
return oss.str();
}

Expand Down
4 changes: 2 additions & 2 deletions src/algorithm/lineSubstring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ find_position(const LineString &ls, const long N, const double target_length,
double seg_length = 0.0;
on_point = false;

for (; idx < N; ++idx) {
for (; idx < static_cast<size_t>(N); ++idx) {
const Point &p = ls.pointN(idx);
const Point &q = ls.pointN(idx + 1);

Expand Down Expand Up @@ -154,7 +154,7 @@ lineSubstring(const LineString &ls, double start, double end)
return std::make_unique<LineString>();
}

const long N = static_cast<long>(ls.numPoints());
const unsigned long N = static_cast<unsigned long>(ls.numPoints());

const bool closed = ls.isClosed();

Expand Down
21 changes: 19 additions & 2 deletions src/capi/sfcgal_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,20 @@ sfcgal_geometry_as_wkb(const sfcgal_geometry_t *pgeom, char **buffer,
{
SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
std::string wkb =
reinterpret_cast<const SFCGAL::Geometry *>(pgeom)->asWkb();
reinterpret_cast<const SFCGAL::Geometry *>(pgeom)->asWkb(
boost::endian::order::native, false);
*buffer = (char *)sfcgal_alloc_handler(wkb.size() + 1); *len = wkb.size();
strncpy(*buffer, wkb.c_str(), *len);)
}

extern "C" void
sfcgal_geometry_as_hexwkb(const sfcgal_geometry_t *pgeom, char **buffer,
size_t *len)
{
SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
std::string wkb =
reinterpret_cast<const SFCGAL::Geometry *>(pgeom)->asWkb(
boost::endian::order::native, true);
*buffer = (char *)sfcgal_alloc_handler(wkb.size() + 1); *len = wkb.size();
strncpy(*buffer, wkb.c_str(), *len);)
}
Expand Down Expand Up @@ -764,7 +777,11 @@ extern "C" auto
sfcgal_io_read_wkb(const char *str, size_t len) -> sfcgal_geometry_t *
{
SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
return SFCGAL::io::readWkb(str, len).release();)
if (len > 2 && str[0] == '0' &&
(str[1] == '0' || str[1] == '1')) return SFCGAL::io::readWkb(str, len,
true)
.release();
return SFCGAL::io::readWkb(str, len, false).release();)
}

extern "C" void
Expand Down
9 changes: 9 additions & 0 deletions src/capi/sfcgal_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ sfcgal_geometry_as_text_decim(const sfcgal_geometry_t *, int numDecimals,
SFCGAL_API void
sfcgal_geometry_as_wkb(const sfcgal_geometry_t *, char **buffer, size_t *len);

/**
* Returns a WKB representation as hexadecimal of the given geometry
* @post buffer is returned allocated and must be freed by the caller
* @ingroup capi
*/
SFCGAL_API void
sfcgal_geometry_as_hexwkb(const sfcgal_geometry_t *, char **buffer,
size_t *len);

/**
* Creates a VTK file of the given geometry
* @ingroup capi
Expand Down
52 changes: 38 additions & 14 deletions src/detail/io/WkbReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,15 @@ class SFCGAL_API WkbReader {
public:
/**
* read WKB from input stream
* @param wkbString hexadecimal ascii string or binary string
* @param asHexString if false, will read the wkb as binary string, else will
* read the string as hex ascii string (ie. 2 chars for 1 byte with values
* matching [0-9A-F]
*/
WkbReader(std::istream &wkbHexString) : _reader(wkbHexString) {}
WkbReader(std::istream &wkbString, bool asHexString = false)
: _reader(wkbString), _asHexString(asHexString)
{
}

auto
readWkb() -> void
Expand Down Expand Up @@ -92,25 +99,36 @@ class SFCGAL_API WkbReader {
auto
read() -> T
{

const size_t nbElements = 2;
const size_t sizeType = sizeof(T);
const size_t totalBytesToRead = nbElements * sizeType;
std::string buffer(totalBytesToRead, '\0');
_reader.readBytes(buffer, totalBytesToRead);
const int base = 16;
const size_t sizeType = sizeof(T);
union {
std::array<std::byte, sizeType> byteArray;
T d;
};

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));
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;
}

_index += sizeType * nbElements;
return d;
}

Expand Down Expand Up @@ -211,7 +229,7 @@ class SFCGAL_API WkbReader {

default:
std::ostringstream oss;
oss << "WkbWriter : '" << geometryType << "' is not supported";
oss << "WkbWriter: type '" << geometryType << "' is not supported";
std::cerr << oss.str() << std::endl;

return {};
Expand Down Expand Up @@ -291,6 +309,12 @@ class SFCGAL_API WkbReader {
*/
tools::InputStreamReader _reader;

/**
* if false, will read the wkb as binary string, else will read the string as
* hex ascii string (ie. 2 chars for 1 byte with values matching [0-9A-F]
*/
bool _asHexString;

/**
* is needed to swap bytes
*/
Expand Down
12 changes: 3 additions & 9 deletions src/detail/io/WkbWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,19 @@ WkbWriter::writeRec(const Geometry &g, boost::endian::order wkbOrder)

default:
std::ostringstream oss;
oss << "WkbWriter : '" << g.geometryType() << "' is not supported";
oss << "WkbWriter: type '" << g.geometryType() << "' is not supported";
BOOST_THROW_EXCEPTION(std::runtime_error(oss.str()));
}
}

void
WkbWriter::write(const Geometry &g, const srid_t &srid,
boost::endian::order wkbOrder, bool asHex)
boost::endian::order wkbOrder)
{

_useSrid = true;
_isEWKB = true;
_srid = srid;
if (asHex) {
_prefix = "\\x";
}

write(g, wkbOrder);
}
Expand All @@ -97,11 +94,8 @@ WkbWriter::write(const Geometry &g, const srid_t &srid,
///
///
void
WkbWriter::write(const Geometry &g, boost::endian::order wkbOrder, bool asHex)
WkbWriter::write(const Geometry &g, boost::endian::order wkbOrder)
{
if (asHex) {
_prefix = "\\x";
}
writeRec(g, wkbOrder);
}

Expand Down
29 changes: 20 additions & 9 deletions src/detail/io/WkbWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,24 @@ namespace SFCGAL::detail::io {
*/
class SFCGAL_API WkbWriter {
public:
WkbWriter(std::ostream &s) : _s(s){};
WkbWriter(std::ostream &s, bool asHexString = false)
: _s(s), _asHexString(asHexString){};

/**
* write WKB for a geometry
* wkbOrder is the native endianness by default.
*/
void
write(const Geometry &g,
boost::endian::order wkbOrder = boost::endian::order::native,
bool asHex = false);
boost::endian::order wkbOrder = boost::endian::order::native);

/**
* write EWKB for a geometry
* wkbOrder is the native endianness by default.
*/
void
write(const Geometry &g, const srid_t &srid,
boost::endian::order wkbOrder = boost::endian::order::native,
bool asHex = false);
boost::endian::order wkbOrder = boost::endian::order::native);

private:
/**
Expand Down Expand Up @@ -120,15 +119,27 @@ class SFCGAL_API WkbWriter {

std::ostream &_s;

/**
* if false, will read the wkb as binary string, else will read the string as
* hex ascii string (ie. 2 chars for 1 byte with values matching [0-9A-F]
*/
bool _asHexString;

template <std::size_t N>
auto
toStream(const std::array<std::byte, N> &arr) -> void
{
for (const std::byte &byteVal : arr) {
_s << _prefix << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(byteVal);
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
Expand Down
28 changes: 16 additions & 12 deletions src/io/wkb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ namespace SFCGAL::io {
///
///
auto
readWkb(std::istream &stream) -> std::unique_ptr<Geometry>
readWkb(std::istream &stream, bool asHexString) -> std::unique_ptr<Geometry>
{
WkbReader wkbReader(stream);
WkbReader wkbReader(stream, asHexString);
wkbReader.readWkb();
return wkbReader.geometry();
}
Expand All @@ -28,10 +28,10 @@ readWkb(std::istream &stream) -> std::unique_ptr<Geometry>
///
///
auto
readWkb(const std::string &s) -> std::unique_ptr<Geometry>
readWkb(const std::string &s, bool asHexString) -> std::unique_ptr<Geometry>
{
std::istringstream iss(s);
WkbReader wkbReader(iss);
WkbReader wkbReader(iss, asHexString);
wkbReader.readWkb();
return wkbReader.geometry();
}
Expand All @@ -40,31 +40,34 @@ readWkb(const std::string &s) -> std::unique_ptr<Geometry>
///
///
auto
readWkb(const char *str, size_t len) -> std::unique_ptr<Geometry>
readWkb(const char *str, size_t len, bool asHexString)
-> std::unique_ptr<Geometry>
{
CharArrayBuffer buf(str, str + len);
std::istream istr(&buf);

return readWkb(istr);
return readWkb(istr, asHexString);
}

/**
* Read a WKB geometry from an input stream
*/
auto
readEwkb(std::istream &stream) -> std::unique_ptr<PreparedGeometry>
readEwkb(std::istream &stream, bool asHexString)
-> std::unique_ptr<PreparedGeometry>
{

WkbReader wkbReader(stream);
WkbReader wkbReader(stream, asHexString);
wkbReader.readWkb();
return wkbReader.preparedGeometry();
}

auto
readEwkb(const std::string &s) -> std::unique_ptr<PreparedGeometry>
readEwkb(const std::string &s, bool asHexString)
-> std::unique_ptr<PreparedGeometry>
{
std::istringstream iss(s);
WkbReader wkbReader(iss);
WkbReader wkbReader(iss, asHexString);
wkbReader.readWkb();
return wkbReader.preparedGeometry();
}
Expand All @@ -73,12 +76,13 @@ readEwkb(const std::string &s) -> std::unique_ptr<PreparedGeometry>
* Read a WKB geometry from a char*
*/
auto
readEwkb(const char *str, size_t len) -> std::unique_ptr<PreparedGeometry>
readEwkb(const char *str, size_t len, bool asHexString)
-> std::unique_ptr<PreparedGeometry>
{
CharArrayBuffer buf(str, str + len);
std::istream istr(&buf);

return readEwkb(istr);
return readEwkb(istr, asHexString);
}

} // namespace SFCGAL::io
Loading

0 comments on commit 6c98e75

Please sign in to comment.