-39
@@ -1,39 +0,0 @@
|
||||
#ifndef OSMIUM_IO_ANY_COMPRESSION_HPP
|
||||
#define OSMIUM_IO_ANY_COMPRESSION_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/bzip2_compression.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/gzip_compression.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_ANY_COMPRESSION_HPP
|
||||
Vendored
-41
@@ -1,41 +0,0 @@
|
||||
#ifndef OSMIUM_IO_ANY_INPUT_HPP
|
||||
#define OSMIUM_IO_ANY_INPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
|
||||
|
||||
#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/xml_input.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_ANY_INPUT_HPP
|
||||
Vendored
-42
@@ -1,42 +0,0 @@
|
||||
#ifndef OSMIUM_IO_ANY_OUTPUT_HPP
|
||||
#define OSMIUM_IO_ANY_OUTPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
|
||||
|
||||
#include <osmium/io/opl_output.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/pbf_output.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/xml_output.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_ANY_OUTPUT_HPP
|
||||
-193
@@ -1,193 +0,0 @@
|
||||
#ifndef OSMIUM_IO_BZIP2_COMPRESSION_HPP
|
||||
#define OSMIUM_IO_BZIP2_COMPRESSION_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#define OSMIUM_LINK_WITH_LIBS_BZ2LIB -lbz2
|
||||
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <bzlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
[[noreturn]] inline void throw_bzip2_error(const std::string& msg, int error) {
|
||||
throw std::runtime_error("bzip2 error: " + msg + ": " + std::to_string(error));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class Bzip2Compressor : public Compressor {
|
||||
|
||||
FILE* m_file;
|
||||
int m_bzerror;
|
||||
BZFILE* m_bzfile;
|
||||
|
||||
public:
|
||||
|
||||
explicit Bzip2Compressor(int fd) :
|
||||
Compressor(),
|
||||
m_file(fdopen(dup(fd), "wb")),
|
||||
m_bzerror(BZ_OK),
|
||||
m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
|
||||
if (!m_bzfile) {
|
||||
detail::throw_bzip2_error("write open failed", m_bzerror);
|
||||
}
|
||||
}
|
||||
|
||||
~Bzip2Compressor() override final {
|
||||
this->close();
|
||||
}
|
||||
|
||||
void write(const std::string& data) override final {
|
||||
int error;
|
||||
::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), data.size());
|
||||
if (error != BZ_OK && error != BZ_STREAM_END) {
|
||||
detail::throw_bzip2_error("write failed", error);
|
||||
}
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
if (m_bzfile) {
|
||||
int error;
|
||||
::BZ2_bzWriteClose(&error, m_bzfile, 0, nullptr, nullptr);
|
||||
m_bzfile = nullptr;
|
||||
if (m_file) {
|
||||
fclose(m_file);
|
||||
}
|
||||
if (error != BZ_OK) {
|
||||
detail::throw_bzip2_error("write close failed", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // class Bzip2Compressor
|
||||
|
||||
class Bzip2Decompressor : public Decompressor {
|
||||
|
||||
FILE* m_file;
|
||||
int m_bzerror;
|
||||
BZFILE* m_bzfile;
|
||||
bool m_stream_end {false};
|
||||
|
||||
public:
|
||||
|
||||
Bzip2Decompressor(int fd) :
|
||||
Decompressor(),
|
||||
m_file(fdopen(dup(fd), "rb")),
|
||||
m_bzerror(BZ_OK),
|
||||
m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
|
||||
if (!m_bzfile) {
|
||||
detail::throw_bzip2_error("read open failed", m_bzerror);
|
||||
}
|
||||
}
|
||||
|
||||
~Bzip2Decompressor() override final {
|
||||
this->close();
|
||||
}
|
||||
|
||||
std::string read() override final {
|
||||
if (m_stream_end) {
|
||||
return std::string();
|
||||
}
|
||||
std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
|
||||
int error;
|
||||
int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), buffer.size());
|
||||
if (error != BZ_OK && error != BZ_STREAM_END) {
|
||||
detail::throw_bzip2_error("read failed", error);
|
||||
}
|
||||
if (error == BZ_STREAM_END) {
|
||||
void* unused;
|
||||
int nunused;
|
||||
if (! feof(m_file)) {
|
||||
::BZ2_bzReadGetUnused(&error, m_bzfile, &unused, &nunused);
|
||||
if (error != BZ_OK) {
|
||||
detail::throw_bzip2_error("get unused failed", error);
|
||||
}
|
||||
std::string unused_data(static_cast<const char*>(unused), static_cast<std::string::size_type>(nunused));
|
||||
::BZ2_bzReadClose(&error, m_bzfile);
|
||||
if (error != BZ_OK) {
|
||||
detail::throw_bzip2_error("read close failed", error);
|
||||
}
|
||||
m_bzfile = ::BZ2_bzReadOpen(&error, m_file, 0, 0, const_cast<void*>(static_cast<const void*>(unused_data.data())), unused_data.size());
|
||||
if (error != BZ_OK) {
|
||||
detail::throw_bzip2_error("read open failed", error);
|
||||
}
|
||||
} else {
|
||||
m_stream_end = true;
|
||||
}
|
||||
}
|
||||
buffer.resize(static_cast<std::string::size_type>(nread));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
if (m_bzfile) {
|
||||
int error;
|
||||
::BZ2_bzReadClose(&error, m_bzfile);
|
||||
m_bzfile = nullptr;
|
||||
if (m_file) {
|
||||
fclose(m_file);
|
||||
}
|
||||
if (error != BZ_OK) {
|
||||
detail::throw_bzip2_error("read close failed", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // class Bzip2Decompressor
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2,
|
||||
[](int fd) { return new osmium::io::Bzip2Compressor(fd); },
|
||||
[](int fd) { return new osmium::io::Bzip2Decompressor(fd); }
|
||||
);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_BZIP2_COMPRESSION_HPP
|
||||
Vendored
-235
@@ -1,235 +0,0 @@
|
||||
#ifndef OSMIUM_IO_COMPRESSION_HPP
|
||||
#define OSMIUM_IO_COMPRESSION_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/read_write.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class Compressor {
|
||||
|
||||
public:
|
||||
|
||||
Compressor() = default;
|
||||
|
||||
virtual ~Compressor() {
|
||||
}
|
||||
|
||||
virtual void write(const std::string& data) = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
}; // class Compressor
|
||||
|
||||
class Decompressor {
|
||||
|
||||
public:
|
||||
|
||||
static constexpr size_t input_buffer_size = 256 * 1024;
|
||||
|
||||
Decompressor() = default;
|
||||
|
||||
Decompressor(const Decompressor&) = delete;
|
||||
Decompressor& operator=(const Decompressor&) = delete;
|
||||
|
||||
Decompressor(Decompressor&&) = delete;
|
||||
Decompressor& operator=(Decompressor&&) = delete;
|
||||
|
||||
virtual ~Decompressor() {
|
||||
}
|
||||
|
||||
virtual std::string read() = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
}; // class Decompressor
|
||||
|
||||
/**
|
||||
* This singleton factory class is used to register compression
|
||||
* algorithms used for reading and writing OSM files.
|
||||
*
|
||||
* For each algorithm we store two functions that construct
|
||||
* a compressor and decompressor object, respectively.
|
||||
*/
|
||||
class CompressionFactory {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<osmium::io::Compressor*(int)> create_compressor_type;
|
||||
typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<const osmium::io::file_compression, std::pair<create_compressor_type, create_decompressor_type>> compression_map_type;
|
||||
|
||||
compression_map_type m_callbacks {};
|
||||
|
||||
CompressionFactory() = default;
|
||||
|
||||
CompressionFactory(const CompressionFactory&) = delete;
|
||||
CompressionFactory& operator=(const CompressionFactory&) = delete;
|
||||
|
||||
CompressionFactory(CompressionFactory&&) = delete;
|
||||
CompressionFactory& operator=(CompressionFactory&&) = delete;
|
||||
|
||||
[[noreturn]] void error(osmium::io::file_compression compression) {
|
||||
std::string error_message {"Support for compression '"};
|
||||
error_message += as_string(compression);
|
||||
error_message += "' not compiled into this binary.";
|
||||
throw std::runtime_error(error_message);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static CompressionFactory& instance() {
|
||||
static CompressionFactory factory;
|
||||
return factory;
|
||||
}
|
||||
|
||||
bool register_compression(osmium::io::file_compression compression, create_compressor_type create_compressor, create_decompressor_type create_decompressor) {
|
||||
compression_map_type::value_type cc(compression, std::make_pair(create_compressor, create_decompressor));
|
||||
return m_callbacks.insert(cc).second;
|
||||
}
|
||||
|
||||
std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, int fd) {
|
||||
auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::Compressor>((it->second.first)(fd));
|
||||
}
|
||||
|
||||
error(compression);
|
||||
}
|
||||
|
||||
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) {
|
||||
auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::Decompressor>((it->second.second)(fd));
|
||||
}
|
||||
|
||||
error(compression);
|
||||
}
|
||||
|
||||
}; // class CompressionFactory
|
||||
|
||||
class NoCompressor : public Compressor {
|
||||
|
||||
int m_fd;
|
||||
|
||||
public:
|
||||
|
||||
NoCompressor(int fd) :
|
||||
Compressor(),
|
||||
m_fd(fd) {
|
||||
}
|
||||
|
||||
~NoCompressor() override final {
|
||||
this->close();
|
||||
}
|
||||
|
||||
void write(const std::string& data) override final {
|
||||
osmium::io::detail::reliable_write(m_fd, data.data(), data.size());
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
if (m_fd >= 0) {
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}; // class NoCompressor
|
||||
|
||||
class NoDecompressor : public Decompressor {
|
||||
|
||||
int m_fd;
|
||||
|
||||
public:
|
||||
|
||||
NoDecompressor(int fd) :
|
||||
Decompressor(),
|
||||
m_fd(fd) {
|
||||
}
|
||||
|
||||
~NoDecompressor() override final {
|
||||
this->close();
|
||||
}
|
||||
|
||||
std::string read() override final {
|
||||
std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
|
||||
ssize_t nread = ::read(m_fd, const_cast<char*>(buffer.data()), buffer.size());
|
||||
if (nread < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "Read failed");
|
||||
}
|
||||
buffer.resize(static_cast<size_t>(nread));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
if (m_fd >= 0) {
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}; // class NoDecompressor
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none,
|
||||
[](int fd) { return new osmium::io::NoCompressor(fd); },
|
||||
[](int fd) { return new osmium::io::NoDecompressor(fd); }
|
||||
);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_COMPRESSION_HPP
|
||||
-160
@@ -1,160 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace thread {
|
||||
template <typename T> class Queue;
|
||||
} // namespace thread
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Virtual base class for all classes reading OSM files in different
|
||||
* formats.
|
||||
*
|
||||
* Do not use this class or derived classes directly. Use the
|
||||
* osmium::io::Reader class instead.
|
||||
*/
|
||||
class InputFormat {
|
||||
|
||||
protected:
|
||||
|
||||
osmium::io::File m_file;
|
||||
osmium::osm_entity_bits::type m_read_which_entities;
|
||||
osmium::thread::Queue<std::string>& m_input_queue;
|
||||
osmium::io::Header m_header {};
|
||||
|
||||
explicit InputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
|
||||
m_file(file),
|
||||
m_read_which_entities(read_which_entities),
|
||||
m_input_queue(input_queue) {
|
||||
m_header.has_multiple_object_versions(m_file.has_multiple_object_versions());
|
||||
}
|
||||
|
||||
InputFormat(const InputFormat&) = delete;
|
||||
InputFormat(InputFormat&&) = delete;
|
||||
|
||||
InputFormat& operator=(const InputFormat&) = delete;
|
||||
InputFormat& operator=(InputFormat&&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~InputFormat() {
|
||||
}
|
||||
|
||||
virtual osmium::memory::Buffer read() = 0;
|
||||
|
||||
virtual void close() {
|
||||
}
|
||||
|
||||
virtual osmium::io::Header header() {
|
||||
return m_header;
|
||||
}
|
||||
|
||||
}; // class InputFormat
|
||||
|
||||
/**
|
||||
* This factory class is used to create objects that read OSM data
|
||||
* written in a specified format.
|
||||
*
|
||||
* Do not use this class directly. Instead use the osmium::io::Reader
|
||||
* class.
|
||||
*/
|
||||
class InputFormatFactory {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<osmium::io::detail::InputFormat*(const osmium::io::File&, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>&)> create_input_type;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<osmium::io::file_format, create_input_type> map_type;
|
||||
|
||||
map_type m_callbacks;
|
||||
|
||||
InputFormatFactory() :
|
||||
m_callbacks() {
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static InputFormatFactory& instance() {
|
||||
static InputFormatFactory factory;
|
||||
return factory;
|
||||
}
|
||||
|
||||
bool register_input_format(osmium::io::file_format format, create_input_type create_function) {
|
||||
if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<osmium::io::detail::InputFormat> create_input(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
|
||||
file.check();
|
||||
|
||||
auto it = m_callbacks.find(file.format());
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::detail::InputFormat>((it->second)(file, read_which_entities, input_queue));
|
||||
}
|
||||
|
||||
throw std::runtime_error(std::string("Support for input format '") + as_string(file.format()) + "' not compiled into this binary.");
|
||||
}
|
||||
|
||||
}; // class InputFormatFactory
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
|
||||
-301
@@ -1,301 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <chrono>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ratio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 104800
|
||||
# include <boost/regex/pending/unicode_iterator.hpp>
|
||||
#else
|
||||
# include <boost_unicode_iterator.hpp>
|
||||
#endif
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Writes out one buffer with OSM data in OPL format.
|
||||
*/
|
||||
class OPLOutputBlock : public osmium::handler::Handler {
|
||||
|
||||
static constexpr size_t tmp_buffer_size = 100;
|
||||
|
||||
osmium::memory::Buffer m_input_buffer;
|
||||
|
||||
std::string m_out;
|
||||
|
||||
char m_tmp_buffer[tmp_buffer_size+1];
|
||||
|
||||
void append_encoded_string(const std::string& data) {
|
||||
boost::u8_to_u32_iterator<std::string::const_iterator> it(data.cbegin(), data.cbegin(), data.cend());
|
||||
boost::u8_to_u32_iterator<std::string::const_iterator> end(data.cend(), data.cend(), data.cend());
|
||||
boost::utf8_output_iterator<std::back_insert_iterator<std::string>> oit(std::back_inserter(m_out));
|
||||
|
||||
for (; it != end; ++it) {
|
||||
uint32_t c = *it;
|
||||
|
||||
// This is a list of Unicode code points that we let
|
||||
// through instead of escaping them. It is incomplete
|
||||
// and can be extended later.
|
||||
// Generally we don't want to let through any character
|
||||
// that has special meaning in the OPL format such as
|
||||
// space, comma, @, etc. and any non-printing characters.
|
||||
if ((0x0021 <= c && c <= 0x0024) ||
|
||||
(0x0026 <= c && c <= 0x002b) ||
|
||||
(0x002d <= c && c <= 0x003c) ||
|
||||
(0x003e <= c && c <= 0x003f) ||
|
||||
(0x0041 <= c && c <= 0x007e) ||
|
||||
(0x00a1 <= c && c <= 0x00ac) ||
|
||||
(0x00ae <= c && c <= 0x05ff)) {
|
||||
*oit = c;
|
||||
} else {
|
||||
m_out += '%';
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, "%04x", c);
|
||||
m_out += m_tmp_buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, "%" PRId64 " v%d d", object.id(), object.version());
|
||||
m_out += m_tmp_buffer;
|
||||
m_out += (object.visible() ? 'V' : 'D');
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, " c%d t", object.changeset());
|
||||
m_out += m_tmp_buffer;
|
||||
m_out += object.timestamp().to_iso();
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, " i%d u", object.uid());
|
||||
m_out += m_tmp_buffer;
|
||||
append_encoded_string(object.user());
|
||||
m_out += " T";
|
||||
bool first = true;
|
||||
for (const auto& tag : object.tags()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
m_out += ',';
|
||||
}
|
||||
append_encoded_string(tag.key());
|
||||
m_out += '=';
|
||||
append_encoded_string(tag.value());
|
||||
}
|
||||
}
|
||||
|
||||
void write_location(const osmium::Location location, const char x, const char y) {
|
||||
if (location) {
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, " %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check());
|
||||
m_out += m_tmp_buffer;
|
||||
} else {
|
||||
m_out += ' ';
|
||||
m_out += x;
|
||||
m_out += ' ';
|
||||
m_out += y;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit OPLOutputBlock(osmium::memory::Buffer&& buffer) :
|
||||
m_input_buffer(std::move(buffer)),
|
||||
m_out(),
|
||||
m_tmp_buffer() {
|
||||
}
|
||||
|
||||
OPLOutputBlock(const OPLOutputBlock&) = delete;
|
||||
OPLOutputBlock& operator=(const OPLOutputBlock&) = delete;
|
||||
|
||||
OPLOutputBlock(OPLOutputBlock&& other) = default;
|
||||
OPLOutputBlock& operator=(OPLOutputBlock&& other) = default;
|
||||
|
||||
std::string operator()() {
|
||||
osmium::apply(m_input_buffer.cbegin(), m_input_buffer.cend(), *this);
|
||||
|
||||
std::string out;
|
||||
std::swap(out, m_out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
m_out += 'n';
|
||||
write_meta(node);
|
||||
write_location(node.location(), 'x', 'y');
|
||||
m_out += '\n';
|
||||
}
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
m_out += 'w';
|
||||
write_meta(way);
|
||||
|
||||
m_out += " N";
|
||||
bool first = true;
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
m_out += ',';
|
||||
}
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, "n%" PRId64, node_ref.ref());
|
||||
m_out += m_tmp_buffer;
|
||||
}
|
||||
m_out += '\n';
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
m_out += 'r';
|
||||
write_meta(relation);
|
||||
|
||||
m_out += " M";
|
||||
bool first = true;
|
||||
for (const auto& member : relation.members()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
m_out += ',';
|
||||
}
|
||||
m_out += item_type_to_char(member.type());
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, "%" PRId64 "@", member.ref());
|
||||
m_out += m_tmp_buffer;
|
||||
m_out += member.role();
|
||||
}
|
||||
m_out += '\n';
|
||||
}
|
||||
|
||||
void changeset(const osmium::Changeset& changeset) {
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, "c%d k%d s", changeset.id(), changeset.num_changes());
|
||||
m_out += m_tmp_buffer;
|
||||
m_out += changeset.created_at().to_iso();
|
||||
m_out += " e";
|
||||
m_out += changeset.closed_at().to_iso();
|
||||
snprintf(m_tmp_buffer, tmp_buffer_size, " i%d u", changeset.uid());
|
||||
m_out += m_tmp_buffer;
|
||||
append_encoded_string(changeset.user());
|
||||
write_location(changeset.bounds().bottom_left(), 'x', 'y');
|
||||
write_location(changeset.bounds().top_right(), 'X', 'Y');
|
||||
m_out += " T";
|
||||
bool first = true;
|
||||
for (const auto& tag : changeset.tags()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
m_out += ',';
|
||||
}
|
||||
append_encoded_string(tag.key());
|
||||
m_out += '=';
|
||||
append_encoded_string(tag.value());
|
||||
}
|
||||
|
||||
m_out += '\n';
|
||||
}
|
||||
|
||||
}; // OPLOutputBlock
|
||||
|
||||
class OPLOutputFormat : public osmium::io::detail::OutputFormat {
|
||||
|
||||
OPLOutputFormat(const OPLOutputFormat&) = delete;
|
||||
OPLOutputFormat& operator=(const OPLOutputFormat&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
OPLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
|
||||
OutputFormat(file, output_queue) {
|
||||
}
|
||||
|
||||
void write_buffer(osmium::memory::Buffer&& buffer) override final {
|
||||
OPLOutputBlock output_block(std::move(buffer));
|
||||
m_output_queue.push(osmium::thread::Pool::instance().submit(std::move(output_block)));
|
||||
while (m_output_queue.size() > 10) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // XXX
|
||||
}
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
std::string out;
|
||||
std::promise<std::string> promise;
|
||||
m_output_queue.push(promise.get_future());
|
||||
promise.set_value(out);
|
||||
}
|
||||
|
||||
}; // class OPLOutputFormat
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
|
||||
[](const osmium::io::File& file, data_queue_type& output_queue) {
|
||||
return new osmium::io::detail::OPLOutputFormat(file, output_queue);
|
||||
});
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/thread/queue.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace memory {
|
||||
class Buffer;
|
||||
}
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
typedef osmium::thread::Queue<std::future<std::string>> data_queue_type;
|
||||
|
||||
/**
|
||||
* Virtual base class for all classes writing OSM files in different
|
||||
* formats.
|
||||
*
|
||||
* Do not use this class or derived classes directly. Use the
|
||||
* osmium::io::Writer class instead.
|
||||
*/
|
||||
class OutputFormat {
|
||||
|
||||
protected:
|
||||
|
||||
osmium::io::File m_file;
|
||||
data_queue_type& m_output_queue;
|
||||
|
||||
public:
|
||||
|
||||
explicit OutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
|
||||
m_file(file),
|
||||
m_output_queue(output_queue) {
|
||||
}
|
||||
|
||||
OutputFormat(const OutputFormat&) = delete;
|
||||
OutputFormat(OutputFormat&&) = delete;
|
||||
|
||||
OutputFormat& operator=(const OutputFormat&) = delete;
|
||||
OutputFormat& operator=(OutputFormat&&) = delete;
|
||||
|
||||
virtual ~OutputFormat() {
|
||||
}
|
||||
|
||||
virtual void write_header(const osmium::io::Header&) {
|
||||
}
|
||||
|
||||
virtual void write_buffer(osmium::memory::Buffer&&) = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
}; // class OutputFormat
|
||||
|
||||
/**
|
||||
* This factory class is used to create objects that write OSM data
|
||||
* into a specified output format.
|
||||
*
|
||||
* Do not use this class directly. Instead use the osmium::io::Writer
|
||||
* class.
|
||||
*/
|
||||
class OutputFormatFactory {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, data_queue_type&)> create_output_type;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<osmium::io::file_format, create_output_type> map_type;
|
||||
|
||||
map_type m_callbacks;
|
||||
|
||||
OutputFormatFactory() :
|
||||
m_callbacks() {
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static OutputFormatFactory& instance() {
|
||||
static OutputFormatFactory factory;
|
||||
return factory;
|
||||
}
|
||||
|
||||
bool register_output_format(osmium::io::file_format format, create_output_type create_function) {
|
||||
if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, data_queue_type& output_queue) {
|
||||
file.check();
|
||||
|
||||
auto it = m_callbacks.find(file.format());
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue));
|
||||
}
|
||||
|
||||
throw std::runtime_error(std::string("Support for output format '") + as_string(file.format()) + "' not compiled into this binary.");
|
||||
}
|
||||
|
||||
}; // class OutputFormatFactory
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
|
||||
Vendored
-79
@@ -1,79 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_PBF_HPP
|
||||
#define OSMIUM_IO_DETAIL_PBF_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#define OSMIUM_LINK_WITH_LIBS_PBF -pthread -lz -lprotobuf-lite -losmpbf
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osmpbf/osmpbf.h>
|
||||
|
||||
// needed for htonl and ntohl
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
inline item_type osmpbf_membertype_to_item_type(const OSMPBF::Relation::MemberType mt) {
|
||||
switch (mt) {
|
||||
case OSMPBF::Relation::NODE:
|
||||
return item_type::node;
|
||||
case OSMPBF::Relation::WAY:
|
||||
return item_type::way;
|
||||
case OSMPBF::Relation::RELATION:
|
||||
return item_type::relation;
|
||||
}
|
||||
}
|
||||
|
||||
inline OSMPBF::Relation::MemberType item_type_to_osmpbf_membertype(const item_type type) {
|
||||
switch (type) {
|
||||
case item_type::node:
|
||||
return OSMPBF::Relation::NODE;
|
||||
case item_type::way:
|
||||
return OSMPBF::Relation::WAY;
|
||||
case item_type::relation:
|
||||
return OSMPBF::Relation::RELATION;
|
||||
default:
|
||||
throw std::runtime_error("Unknown relation member type");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_PBF_HPP
|
||||
-681
@@ -1,681 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <ratio>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/zlib.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/thread/name.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/thread/queue.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class PBFPrimitiveBlockParser {
|
||||
|
||||
static constexpr size_t initial_buffer_size = 10 * 1024;
|
||||
|
||||
const void* m_data;
|
||||
const size_t m_size;
|
||||
|
||||
const OSMPBF::StringTable* m_stringtable;
|
||||
int64_t m_lon_offset;
|
||||
int64_t m_lat_offset;
|
||||
int64_t m_date_factor;
|
||||
int32_t m_granularity;
|
||||
|
||||
osmium::osm_entity_bits::type m_read_types;
|
||||
|
||||
osmium::memory::Buffer m_buffer;
|
||||
|
||||
PBFPrimitiveBlockParser(const PBFPrimitiveBlockParser&) = delete;
|
||||
PBFPrimitiveBlockParser(PBFPrimitiveBlockParser&&) = delete;
|
||||
|
||||
PBFPrimitiveBlockParser& operator=(const PBFPrimitiveBlockParser&) = delete;
|
||||
PBFPrimitiveBlockParser& operator=(PBFPrimitiveBlockParser&&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
explicit PBFPrimitiveBlockParser(const void* data, const size_t size, osmium::osm_entity_bits::type read_types) :
|
||||
m_data(data),
|
||||
m_size(size),
|
||||
m_stringtable(nullptr),
|
||||
m_lon_offset(0),
|
||||
m_lat_offset(0),
|
||||
m_date_factor(1000),
|
||||
m_granularity(100),
|
||||
m_read_types(read_types),
|
||||
m_buffer(initial_buffer_size) {
|
||||
}
|
||||
|
||||
~PBFPrimitiveBlockParser() = default;
|
||||
|
||||
osmium::memory::Buffer operator()() {
|
||||
OSMPBF::PrimitiveBlock pbf_primitive_block;
|
||||
if (!pbf_primitive_block.ParseFromArray(m_data, m_size)) {
|
||||
throw std::runtime_error("Failed to parse PrimitiveBlock.");
|
||||
}
|
||||
|
||||
m_stringtable = &pbf_primitive_block.stringtable();
|
||||
m_lon_offset = pbf_primitive_block.lon_offset();
|
||||
m_lat_offset = pbf_primitive_block.lat_offset();
|
||||
m_date_factor = pbf_primitive_block.date_granularity() / 1000;
|
||||
m_granularity = pbf_primitive_block.granularity();
|
||||
|
||||
for (int i=0; i < pbf_primitive_block.primitivegroup_size(); ++i) {
|
||||
const OSMPBF::PrimitiveGroup& group = pbf_primitive_block.primitivegroup(i);
|
||||
|
||||
if (group.has_dense()) {
|
||||
if (m_read_types & osmium::osm_entity_bits::node) parse_dense_node_group(group);
|
||||
} else if (group.ways_size() != 0) {
|
||||
if (m_read_types & osmium::osm_entity_bits::way) parse_way_group(group);
|
||||
} else if (group.relations_size() != 0) {
|
||||
if (m_read_types & osmium::osm_entity_bits::relation) parse_relation_group(group);
|
||||
} else if (group.nodes_size() != 0) {
|
||||
if (m_read_types & osmium::osm_entity_bits::node) parse_node_group(group);
|
||||
} else {
|
||||
throw std::runtime_error("Group of unknown type.");
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(m_buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <class TBuilder, class TPBFObject>
|
||||
void parse_attributes(TBuilder& builder, const TPBFObject& pbf_object) {
|
||||
auto& object = builder.object();
|
||||
|
||||
object.id(pbf_object.id());
|
||||
|
||||
if (pbf_object.has_info()) {
|
||||
object.version(pbf_object.info().version())
|
||||
.changeset(pbf_object.info().changeset())
|
||||
.timestamp(pbf_object.info().timestamp() * m_date_factor)
|
||||
.uid_from_signed(pbf_object.info().uid());
|
||||
if (pbf_object.info().has_visible()) {
|
||||
object.visible(pbf_object.info().visible());
|
||||
}
|
||||
builder.add_user(m_stringtable->s(pbf_object.info().user_sid()).data());
|
||||
} else {
|
||||
builder.add_user("");
|
||||
}
|
||||
}
|
||||
|
||||
void parse_node_group(const OSMPBF::PrimitiveGroup& group) {
|
||||
for (int i=0; i < group.nodes_size(); ++i) {
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
const OSMPBF::Node& pbf_node = group.nodes(i);
|
||||
parse_attributes(builder, pbf_node);
|
||||
|
||||
if (builder.object().visible()) {
|
||||
builder.object().location(osmium::Location(
|
||||
(pbf_node.lon() * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
|
||||
(pbf_node.lat() * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
|
||||
}
|
||||
|
||||
if (pbf_node.keys_size() > 0) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
for (int tag=0; tag < pbf_node.keys_size(); ++tag) {
|
||||
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_node.keys(tag))).data(),
|
||||
m_stringtable->s(static_cast<int>(pbf_node.vals(tag))).data());
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
}
|
||||
|
||||
void parse_way_group(const OSMPBF::PrimitiveGroup& group) {
|
||||
for (int i=0; i < group.ways_size(); ++i) {
|
||||
osmium::builder::WayBuilder builder(m_buffer);
|
||||
const OSMPBF::Way& pbf_way = group.ways(i);
|
||||
parse_attributes(builder, pbf_way);
|
||||
|
||||
if (pbf_way.refs_size() > 0) {
|
||||
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
|
||||
int64_t ref = 0;
|
||||
for (int n=0; n < pbf_way.refs_size(); ++n) {
|
||||
ref += pbf_way.refs(n);
|
||||
wnl_builder.add_node_ref(ref);
|
||||
}
|
||||
}
|
||||
|
||||
if (pbf_way.keys_size() > 0) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
for (int tag=0; tag < pbf_way.keys_size(); ++tag) {
|
||||
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_way.keys(tag))).data(),
|
||||
m_stringtable->s(static_cast<int>(pbf_way.vals(tag))).data());
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
}
|
||||
|
||||
void parse_relation_group(const OSMPBF::PrimitiveGroup& group) {
|
||||
for (int i=0; i < group.relations_size(); ++i) {
|
||||
osmium::builder::RelationBuilder builder(m_buffer);
|
||||
const OSMPBF::Relation& pbf_relation = group.relations(i);
|
||||
parse_attributes(builder, pbf_relation);
|
||||
|
||||
if (pbf_relation.types_size() > 0) {
|
||||
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
|
||||
int64_t ref = 0;
|
||||
for (int n=0; n < pbf_relation.types_size(); ++n) {
|
||||
ref += pbf_relation.memids(n);
|
||||
rml_builder.add_member(osmpbf_membertype_to_item_type(pbf_relation.types(n)), ref, m_stringtable->s(pbf_relation.roles_sid(n)).data());
|
||||
}
|
||||
}
|
||||
|
||||
if (pbf_relation.keys_size() > 0) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
for (int tag=0; tag < pbf_relation.keys_size(); ++tag) {
|
||||
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_relation.keys(tag))).data(),
|
||||
m_stringtable->s(static_cast<int>(pbf_relation.vals(tag))).data());
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
}
|
||||
|
||||
int add_tags(const OSMPBF::DenseNodes& dense, int n, osmium::builder::NodeBuilder* builder) {
|
||||
if (n >= dense.keys_vals_size()) {
|
||||
return n;
|
||||
}
|
||||
|
||||
if (dense.keys_vals(n) == 0) {
|
||||
return n+1;
|
||||
}
|
||||
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, builder);
|
||||
|
||||
while (n < dense.keys_vals_size()) {
|
||||
int tag_key_pos = dense.keys_vals(n++);
|
||||
|
||||
if (tag_key_pos == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
tl_builder.add_tag(m_stringtable->s(tag_key_pos).data(),
|
||||
m_stringtable->s(dense.keys_vals(n)).data());
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void parse_dense_node_group(const OSMPBF::PrimitiveGroup& group) {
|
||||
int64_t last_dense_id = 0;
|
||||
int64_t last_dense_latitude = 0;
|
||||
int64_t last_dense_longitude = 0;
|
||||
int64_t last_dense_uid = 0;
|
||||
int64_t last_dense_user_sid = 0;
|
||||
int64_t last_dense_changeset = 0;
|
||||
int64_t last_dense_timestamp = 0;
|
||||
int last_dense_tag = 0;
|
||||
|
||||
const OSMPBF::DenseNodes& dense = group.dense();
|
||||
|
||||
for (int i=0; i < dense.id_size(); ++i) {
|
||||
bool visible = true;
|
||||
|
||||
last_dense_id += dense.id(i);
|
||||
last_dense_latitude += dense.lat(i);
|
||||
last_dense_longitude += dense.lon(i);
|
||||
|
||||
if (dense.has_denseinfo()) {
|
||||
last_dense_changeset += dense.denseinfo().changeset(i);
|
||||
last_dense_timestamp += dense.denseinfo().timestamp(i);
|
||||
last_dense_uid += dense.denseinfo().uid(i);
|
||||
last_dense_user_sid += dense.denseinfo().user_sid(i);
|
||||
if (dense.denseinfo().visible_size() > 0) {
|
||||
visible = dense.denseinfo().visible(i);
|
||||
}
|
||||
assert(last_dense_changeset >= 0);
|
||||
assert(last_dense_timestamp >= 0);
|
||||
assert(last_dense_uid >= -1);
|
||||
assert(last_dense_user_sid >= 0);
|
||||
}
|
||||
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
node.id(last_dense_id);
|
||||
|
||||
if (dense.has_denseinfo()) {
|
||||
auto v = dense.denseinfo().version(i);
|
||||
assert(v > 0);
|
||||
node.version(static_cast<osmium::object_version_type>(v));
|
||||
node.changeset(last_dense_changeset);
|
||||
node.timestamp(last_dense_timestamp * m_date_factor);
|
||||
node.uid_from_signed(last_dense_uid);
|
||||
node.visible(visible);
|
||||
builder.add_user(m_stringtable->s(last_dense_user_sid).data());
|
||||
} else {
|
||||
builder.add_user("");
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
builder.object().location(osmium::Location(
|
||||
(last_dense_longitude * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
|
||||
(last_dense_latitude * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
|
||||
}
|
||||
|
||||
last_dense_tag = add_tags(dense, last_dense_tag, &builder);
|
||||
m_buffer.commit();
|
||||
}
|
||||
}
|
||||
|
||||
}; // class PBFPrimitiveBlockParser
|
||||
|
||||
typedef osmium::thread::Queue<std::future<osmium::memory::Buffer>> queue_type;
|
||||
|
||||
class InputQueueReader {
|
||||
|
||||
osmium::thread::Queue<std::string>& m_queue;
|
||||
std::string m_buffer {};
|
||||
|
||||
public:
|
||||
|
||||
InputQueueReader(osmium::thread::Queue<std::string>& queue) :
|
||||
m_queue(queue) {
|
||||
}
|
||||
|
||||
bool operator()(unsigned char* data, size_t size) {
|
||||
while (m_buffer.size() < size) {
|
||||
std::string new_data;
|
||||
m_queue.wait_and_pop(new_data);
|
||||
if (new_data.empty()) {
|
||||
return false;
|
||||
}
|
||||
m_buffer += new_data;
|
||||
}
|
||||
memcpy(data, m_buffer.data(), size);
|
||||
m_buffer.erase(0, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class TDerived>
|
||||
class BlobParser {
|
||||
|
||||
protected:
|
||||
|
||||
std::shared_ptr<unsigned char> m_input_buffer;
|
||||
const int m_size;
|
||||
const int m_blob_num;
|
||||
InputQueueReader& m_input_queue_reader;
|
||||
|
||||
BlobParser(const int size, const int blob_num, InputQueueReader& input_queue_reader) :
|
||||
m_input_buffer(new unsigned char[size], [](unsigned char* ptr) { delete[] ptr; }),
|
||||
m_size(size),
|
||||
m_blob_num(blob_num),
|
||||
m_input_queue_reader(input_queue_reader) {
|
||||
if (size < 0 || size > OSMPBF::max_uncompressed_blob_size) {
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "invalid blob size: " << size;
|
||||
throw std::runtime_error(errmsg.str());
|
||||
}
|
||||
if (! input_queue_reader(m_input_buffer.get(), size)) {
|
||||
// EOF
|
||||
throw std::runtime_error("read error (EOF)");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void doit() {
|
||||
OSMPBF::Blob pbf_blob;
|
||||
if (!pbf_blob.ParseFromArray(m_input_buffer.get(), m_size)) {
|
||||
throw std::runtime_error("failed to parse blob");
|
||||
}
|
||||
|
||||
if (pbf_blob.has_raw()) {
|
||||
static_cast<TDerived*>(this)->handle_blob(pbf_blob.raw());
|
||||
return;
|
||||
} else if (pbf_blob.has_zlib_data()) {
|
||||
auto raw_size = pbf_blob.raw_size();
|
||||
assert(raw_size >= 0);
|
||||
assert(raw_size <= OSMPBF::max_uncompressed_blob_size);
|
||||
|
||||
std::string unpack_buffer { osmium::io::detail::zlib_uncompress(pbf_blob.zlib_data(), static_cast<unsigned long>(raw_size)) };
|
||||
static_cast<TDerived*>(this)->handle_blob(unpack_buffer);
|
||||
return;
|
||||
} else if (pbf_blob.has_lzma_data()) {
|
||||
throw std::runtime_error("lzma blobs not implemented");
|
||||
} else {
|
||||
throw std::runtime_error("Blob contains no data");
|
||||
}
|
||||
}
|
||||
|
||||
osmium::memory::Buffer operator()() {
|
||||
OSMPBF::Blob pbf_blob;
|
||||
if (!pbf_blob.ParseFromArray(m_input_buffer.get(), m_size)) {
|
||||
throw std::runtime_error("failed to parse blob");
|
||||
}
|
||||
|
||||
if (pbf_blob.has_raw()) {
|
||||
return static_cast<TDerived*>(this)->handle_blob(pbf_blob.raw());
|
||||
} else if (pbf_blob.has_zlib_data()) {
|
||||
auto raw_size = pbf_blob.raw_size();
|
||||
assert(raw_size >= 0);
|
||||
assert(raw_size <= OSMPBF::max_uncompressed_blob_size);
|
||||
|
||||
std::string unpack_buffer { osmium::io::detail::zlib_uncompress(pbf_blob.zlib_data(), static_cast<unsigned long>(raw_size)) };
|
||||
return static_cast<TDerived*>(this)->handle_blob(unpack_buffer);
|
||||
} else if (pbf_blob.has_lzma_data()) {
|
||||
throw std::runtime_error("lzma blobs not implemented");
|
||||
} else {
|
||||
throw std::runtime_error("Blob contains no data");
|
||||
}
|
||||
}
|
||||
|
||||
}; // class BlobParser;
|
||||
|
||||
class HeaderBlobParser : public BlobParser<HeaderBlobParser> {
|
||||
|
||||
osmium::io::Header& m_header;
|
||||
|
||||
void handle_blob(const std::string& data) {
|
||||
OSMPBF::HeaderBlock pbf_header_block;
|
||||
if (!pbf_header_block.ParseFromArray(data.data(), data.size())) {
|
||||
throw std::runtime_error("Failed to parse HeaderBlock.");
|
||||
}
|
||||
|
||||
for (int i=0; i < pbf_header_block.required_features_size(); ++i) {
|
||||
const std::string& feature = pbf_header_block.required_features(i);
|
||||
|
||||
if (feature == "OsmSchema-V0.6") continue;
|
||||
if (feature == "DenseNodes") {
|
||||
m_header.set("pbf_dense_nodes", true);
|
||||
continue;
|
||||
}
|
||||
if (feature == "HistoricalInformation") {
|
||||
m_header.has_multiple_object_versions(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Required feature not supported: " << feature;
|
||||
throw std::runtime_error(errmsg.str());
|
||||
}
|
||||
|
||||
if (pbf_header_block.has_writingprogram()) {
|
||||
m_header.set("generator", pbf_header_block.writingprogram());
|
||||
}
|
||||
|
||||
if (pbf_header_block.has_bbox()) {
|
||||
const OSMPBF::HeaderBBox& pbf_bbox = pbf_header_block.bbox();
|
||||
const int64_t resolution_convert = OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision;
|
||||
osmium::Box box;
|
||||
box.extend(osmium::Location(pbf_bbox.left() / resolution_convert, pbf_bbox.bottom() / resolution_convert));
|
||||
box.extend(osmium::Location(pbf_bbox.right() / resolution_convert, pbf_bbox.top() / resolution_convert));
|
||||
m_header.add_box(box);
|
||||
}
|
||||
|
||||
if (pbf_header_block.has_osmosis_replication_timestamp()) {
|
||||
m_header.set("osmosis_replication_timestamp", osmium::Timestamp(pbf_header_block.osmosis_replication_timestamp()).to_iso());
|
||||
}
|
||||
|
||||
if (pbf_header_block.has_osmosis_replication_sequence_number()) {
|
||||
m_header.set("osmosis_replication_sequence_number", std::to_string(pbf_header_block.osmosis_replication_sequence_number()));
|
||||
}
|
||||
|
||||
if (pbf_header_block.has_osmosis_replication_base_url()) {
|
||||
m_header.set("osmosis_replication_base_url", pbf_header_block.osmosis_replication_base_url());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
friend class BlobParser;
|
||||
|
||||
HeaderBlobParser(const int size, InputQueueReader& input_queue_reader, osmium::io::Header& header) :
|
||||
BlobParser(size, 0, input_queue_reader),
|
||||
m_header(header) {
|
||||
}
|
||||
|
||||
}; // class HeaderBlobParser
|
||||
|
||||
class DataBlobParser : public BlobParser<DataBlobParser> {
|
||||
|
||||
osmium::osm_entity_bits::type m_read_types;
|
||||
|
||||
osmium::memory::Buffer handle_blob(const std::string& data) {
|
||||
PBFPrimitiveBlockParser parser(data.data(), data.size(), m_read_types);
|
||||
return std::move(parser());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
friend class BlobParser;
|
||||
|
||||
DataBlobParser(const int size, const int blob_num, InputQueueReader& input_queue_reader, osmium::osm_entity_bits::type read_types) :
|
||||
BlobParser(size, blob_num, input_queue_reader),
|
||||
m_read_types(read_types) {
|
||||
}
|
||||
|
||||
}; // class DataBlobParser
|
||||
|
||||
/**
|
||||
* Class for parsing PBF files.
|
||||
*/
|
||||
class PBFInputFormat : public osmium::io::detail::InputFormat {
|
||||
|
||||
bool m_use_thread_pool;
|
||||
queue_type m_queue;
|
||||
const size_t m_max_work_queue_size;
|
||||
const size_t m_max_buffer_queue_size;
|
||||
std::atomic<bool> m_done;
|
||||
std::thread m_reader;
|
||||
OSMPBF::BlobHeader m_blob_header;
|
||||
InputQueueReader m_input_queue_reader;
|
||||
|
||||
/**
|
||||
* Read BlobHeader by first reading the size and then the BlobHeader.
|
||||
* The BlobHeader contains a type field (which is checked against
|
||||
* the expected type) and a size field.
|
||||
*
|
||||
* @param expected_type Expected type of data ("OSMHeader" or "OSMData").
|
||||
* @return Size of the data read from BlobHeader (0 on EOF).
|
||||
*/
|
||||
size_t read_blob_header(const char* expected_type) {
|
||||
uint32_t size_in_network_byte_order;
|
||||
|
||||
if (! m_input_queue_reader(reinterpret_cast<unsigned char*>(&size_in_network_byte_order), sizeof(size_in_network_byte_order))) {
|
||||
return 0; // EOF
|
||||
}
|
||||
|
||||
uint32_t size = ntohl(size_in_network_byte_order);
|
||||
if (size > static_cast<uint32_t>(OSMPBF::max_blob_header_size)) {
|
||||
throw std::runtime_error("Invalid BlobHeader size");
|
||||
}
|
||||
|
||||
unsigned char blob_header_buffer[OSMPBF::max_blob_header_size];
|
||||
if (! m_input_queue_reader(blob_header_buffer, size)) {
|
||||
throw std::runtime_error("Read error.");
|
||||
}
|
||||
|
||||
if (!m_blob_header.ParseFromArray(blob_header_buffer, static_cast<int>(size))) {
|
||||
throw std::runtime_error("Failed to parse BlobHeader.");
|
||||
}
|
||||
|
||||
if (std::strcmp(m_blob_header.type().c_str(), expected_type)) {
|
||||
throw std::runtime_error("Blob does not have expected type (OSMHeader in first Blob, OSMData in following Blobs).");
|
||||
}
|
||||
|
||||
return static_cast<size_t>(m_blob_header.datasize());
|
||||
}
|
||||
|
||||
void parse_osm_data(osmium::osm_entity_bits::type read_types) {
|
||||
osmium::thread::set_thread_name("_osmium_pbf_in");
|
||||
int n=0;
|
||||
while (size_t size = read_blob_header("OSMData")) {
|
||||
DataBlobParser data_blob_parser(size, n, m_input_queue_reader, read_types);
|
||||
|
||||
if (m_use_thread_pool) {
|
||||
m_queue.push(osmium::thread::Pool::instance().submit(data_blob_parser));
|
||||
|
||||
// if the work queue is getting too large, wait for a while
|
||||
while (!m_done && osmium::thread::Pool::instance().queue_size() >= m_max_work_queue_size) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
} else {
|
||||
std::promise<osmium::memory::Buffer> promise;
|
||||
m_queue.push(promise.get_future());
|
||||
promise.set_value(data_blob_parser());
|
||||
}
|
||||
++n;
|
||||
|
||||
// wait if the backlog of buffers with parsed data is too large
|
||||
while (!m_done && m_queue.size() > m_max_buffer_queue_size) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
if (m_done) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_done = true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Instantiate PBF Parser
|
||||
*
|
||||
* @param file osmium::io::File instance describing file to be read from.
|
||||
* @param read_which_entities Which types of OSM entities (nodes, ways, relations, changesets) should be parsed?
|
||||
* @param input_queue String queue where data is read from.
|
||||
*/
|
||||
PBFInputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
|
||||
osmium::io::detail::InputFormat(file, read_which_entities, input_queue),
|
||||
m_use_thread_pool(true),
|
||||
m_queue(),
|
||||
m_max_work_queue_size(10), // XXX tune these settings
|
||||
m_max_buffer_queue_size(20), // XXX tune these settings
|
||||
m_done(false),
|
||||
m_input_queue_reader(input_queue) {
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
|
||||
// handle OSMHeader
|
||||
size_t size = read_blob_header("OSMHeader");
|
||||
|
||||
{
|
||||
HeaderBlobParser header_blob_parser(size, m_input_queue_reader, m_header);
|
||||
header_blob_parser.doit();
|
||||
}
|
||||
|
||||
if (m_read_which_entities != osmium::osm_entity_bits::nothing) {
|
||||
m_reader = std::thread(&PBFInputFormat::parse_osm_data, this, m_read_which_entities);
|
||||
}
|
||||
}
|
||||
|
||||
~PBFInputFormat() {
|
||||
m_done = true;
|
||||
if (m_reader.joinable()) {
|
||||
m_reader.join();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next buffer with OSM data read from the PBF file.
|
||||
* Blocks if data is not available yet.
|
||||
* Returns an empty buffer at end of input.
|
||||
*/
|
||||
osmium::memory::Buffer read() override {
|
||||
if (!m_done || !m_queue.empty()) {
|
||||
std::future<osmium::memory::Buffer> buffer_future;
|
||||
m_queue.wait_and_pop(buffer_future);
|
||||
return std::move(buffer_future.get());
|
||||
}
|
||||
|
||||
return osmium::memory::Buffer();
|
||||
}
|
||||
|
||||
}; // class PBFInputFormat
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_pbf_input = osmium::io::detail::InputFormatFactory::instance().register_input_format(osmium::io::file_format::pbf,
|
||||
[](const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
|
||||
return new osmium::io::detail::PBFInputFormat(file, read_which_entities, input_queue);
|
||||
});
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
|
||||
-950
@@ -1,950 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
About the .osm.pbf file format
|
||||
This is an excerpt of <http://wiki.openstreetmap.org/wiki/PBF_Format>
|
||||
|
||||
The .osm.pbf format and it's derived formats (.osh.pbf and .osc.pbf) are encoded
|
||||
using googles protobuf library for the low-level storage. They are constructed
|
||||
by nesting data on two levels:
|
||||
|
||||
On the lower level the file is constructed using BlobHeaders and Blobs. A .osm.pbf
|
||||
file contains multiple sequences of
|
||||
1. a 4-byte header size, stored in network-byte-order
|
||||
2. a BlobHeader of exactly this size
|
||||
3. a Blob
|
||||
|
||||
The BlobHeader tells the reader about the type and size of the following Blob. The
|
||||
Blob can contain data in raw or zlib-compressed form. After uncompressing the blob
|
||||
it is treated differently depending on the type specified in the BlobHeader.
|
||||
|
||||
The contents of the Blob belongs to the higher level. It contains either an HeaderBlock
|
||||
(type="OSMHeader") or an PrimitiveBlock (type="OSMData"). The file needs to have
|
||||
at least one HeaderBlock before the first PrimitiveBlock.
|
||||
|
||||
The HeaderBlock contains meta-information like the writing program or a bbox. It may
|
||||
also contain multiple "required features" that describe what kinds of input a
|
||||
reading program needs to handle in order to fully understand the files' contents.
|
||||
|
||||
The PrimitiveBlock can store multiple types of objects (i.e. 5 nodes, 2 ways and
|
||||
1 relation). It contains one or more PrimitiveGroup which in turn contain multiple
|
||||
nodes, ways or relations. A PrimitiveGroup should only contain one kind of object.
|
||||
|
||||
There's a special kind of "object type" called dense-nodes. It is used to store nodes
|
||||
in a very dense format, avoiding message overheads and using delta-encoding for nearly
|
||||
all ids.
|
||||
|
||||
All Strings are stored as indexes to rows in a StringTable. The StringTable contains
|
||||
one row for each used string, so strings that are used multiple times need to be
|
||||
stored only once. The StringTable is sorted by usage-count, so the most often used
|
||||
string is stored at index 1.
|
||||
|
||||
A simple outline of a .osm.pbf file could look like this:
|
||||
|
||||
4-bytes header size
|
||||
BlobHeader
|
||||
Blob
|
||||
HeaderBlock
|
||||
4-bytes header size
|
||||
BlobHeader
|
||||
Blob
|
||||
PrimitiveBlock
|
||||
StringTable
|
||||
PrimitiveGroup
|
||||
5 nodes
|
||||
PrimitiveGroup
|
||||
2 ways
|
||||
PrimitiveGroup
|
||||
1 relation
|
||||
|
||||
More complete outlines of real .osm.pbf files can be created using the osmpbf-outline tool:
|
||||
<https://github.com/MaZderMind/OSM-binary/tree/osmpbf-outline>
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <ratio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <time.h>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/pbf_stringtable.hpp>
|
||||
#include <osmium/io/detail/zlib.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Serialize a protobuf message into a Blob, optionally apply compression
|
||||
* and return it together with a BlobHeader ready to be written to a file.
|
||||
*
|
||||
* @param type Type-string used in the BlobHeader.
|
||||
* @param msg Protobuf-message.
|
||||
* @param use_compression Should the output be compressed using zlib?
|
||||
*/
|
||||
std::string serialize_blob(const std::string& type, const google::protobuf::MessageLite& msg, bool use_compression) {
|
||||
OSMPBF::Blob pbf_blob;
|
||||
|
||||
{
|
||||
std::string content;
|
||||
msg.SerializeToString(&content);
|
||||
|
||||
pbf_blob.set_raw_size(content.size());
|
||||
|
||||
if (use_compression) {
|
||||
pbf_blob.set_zlib_data(osmium::io::detail::zlib_compress(content));
|
||||
} else {
|
||||
pbf_blob.set_raw(content);
|
||||
}
|
||||
}
|
||||
|
||||
std::string blob_data;
|
||||
pbf_blob.SerializeToString(&blob_data);
|
||||
|
||||
OSMPBF::BlobHeader pbf_blob_header;
|
||||
pbf_blob_header.set_type(type);
|
||||
pbf_blob_header.set_datasize(blob_data.size());
|
||||
|
||||
std::string blob_header_data;
|
||||
pbf_blob_header.SerializeToString(&blob_header_data);
|
||||
|
||||
uint32_t sz = htonl(blob_header_data.size());
|
||||
|
||||
// write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
|
||||
std::string output;
|
||||
output.reserve(sizeof(sz) + blob_header_data.size() + blob_data.size());
|
||||
output.append(reinterpret_cast<const char*>(&sz), sizeof(sz));
|
||||
output.append(blob_header_data);
|
||||
output.append(blob_data);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class PBFOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
|
||||
|
||||
/**
|
||||
* This class models a variable that keeps track of the value
|
||||
* it was last set to and returns the delta between old and
|
||||
* new value from the update() call.
|
||||
*/
|
||||
template <typename T>
|
||||
class Delta {
|
||||
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
|
||||
Delta() :
|
||||
m_value(0) {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
T update(T new_value) {
|
||||
using std::swap;
|
||||
swap(m_value, new_value);
|
||||
return m_value - new_value;
|
||||
}
|
||||
|
||||
}; // class Delta
|
||||
|
||||
/**
|
||||
* Maximum number of items in a primitive block.
|
||||
*
|
||||
* The uncompressed length of a Blob *should* be less
|
||||
* than 16 megabytes and *must* be less than 32 megabytes.
|
||||
*
|
||||
* A block may contain any number of entities, as long as
|
||||
* the size limits for the surrounding blob are obeyed.
|
||||
* However, for simplicity, the current Osmosis (0.38)
|
||||
* as well as Osmium implementation always
|
||||
* uses at most 8k entities in a block.
|
||||
*/
|
||||
static constexpr uint32_t max_block_contents = 8000;
|
||||
|
||||
/**
|
||||
* The output buffer (block) will be filled to about
|
||||
* 95% and then written to disk. This leaves more than
|
||||
* enough space for the string table (which typically
|
||||
* needs about 0.1 to 0.3% of the block size).
|
||||
*/
|
||||
static constexpr int buffer_fill_percent = 95;
|
||||
|
||||
/**
|
||||
* protobuf-struct of a HeaderBlock
|
||||
*/
|
||||
OSMPBF::HeaderBlock pbf_header_block;
|
||||
|
||||
/**
|
||||
* protobuf-struct of a PrimitiveBlock
|
||||
*/
|
||||
OSMPBF::PrimitiveBlock pbf_primitive_block;
|
||||
|
||||
/**
|
||||
* pointer to PrimitiveGroups inside the current PrimitiveBlock,
|
||||
* used for writing nodes, ways or relations
|
||||
*/
|
||||
OSMPBF::PrimitiveGroup* pbf_nodes;
|
||||
OSMPBF::PrimitiveGroup* pbf_ways;
|
||||
OSMPBF::PrimitiveGroup* pbf_relations;
|
||||
|
||||
/**
|
||||
* To flexibly handle multiple resolutions, the granularity, or
|
||||
* resolution used for representing locations is adjustable in
|
||||
* multiples of 1 nanodegree. The default scaling factor is 100
|
||||
* nanodegrees, corresponding to about ~1cm at the equator.
|
||||
* This is the current resolution of the OSM database.
|
||||
*/
|
||||
int m_location_granularity;
|
||||
|
||||
/**
|
||||
* The granularity used for representing timestamps is also adjustable in
|
||||
* multiples of 1 millisecond. The default scaling factor is 1000
|
||||
* milliseconds, which is the current resolution of the OSM database.
|
||||
*/
|
||||
int m_date_granularity;
|
||||
|
||||
/**
|
||||
* should nodes be serialized into the dense format?
|
||||
*
|
||||
* nodes can be encoded one of two ways, as a Node
|
||||
* (m_use_dense_nodes = false) and a special dense format.
|
||||
* In the dense format, all information is stored 'column wise',
|
||||
* as an array of ID's, array of latitudes, and array of
|
||||
* longitudes. Each column is delta-encoded. This reduces
|
||||
* header overheads and allows delta-coding to work very effectively.
|
||||
*/
|
||||
bool m_use_dense_nodes {true};
|
||||
|
||||
/**
|
||||
* should the PBF blobs contain zlib compressed data?
|
||||
*
|
||||
* the zlib compression is optional, it's possible to store the
|
||||
* blobs in raw format. Disabling the compression can improve the
|
||||
* writing speed a little but the output will be 2x to 3x bigger.
|
||||
*/
|
||||
bool m_use_compression {true};
|
||||
|
||||
/**
|
||||
* While the .osm.pbf-format is able to carry all meta information, it is
|
||||
* also able to omit this information to reduce size.
|
||||
*/
|
||||
bool m_should_add_metadata {true};
|
||||
|
||||
/**
|
||||
* Should the visible flag be added on objects?
|
||||
*/
|
||||
bool m_add_visible;
|
||||
|
||||
/**
|
||||
* counter used to quickly check the number of objects stored inside
|
||||
* the current PrimitiveBlock. When the counter reaches max_block_contents
|
||||
* the PrimitiveBlock is serialized into a Blob and flushed to the file.
|
||||
*
|
||||
* this check is performed in check_block_contents_counter() which is
|
||||
* called once for each object.
|
||||
*/
|
||||
uint16_t primitive_block_contents;
|
||||
uint32_t primitive_block_size;
|
||||
|
||||
// StringTable management
|
||||
StringTable string_table;
|
||||
|
||||
/**
|
||||
* These variables are used to calculate the
|
||||
* delta-encoding while storing dense-nodes. It holds the last seen values
|
||||
* from which the difference is stored into the protobuf.
|
||||
*/
|
||||
Delta<int64_t> m_delta_id;
|
||||
Delta<int64_t> m_delta_lat;
|
||||
Delta<int64_t> m_delta_lon;
|
||||
Delta<int64_t> m_delta_timestamp;
|
||||
Delta<int64_t> m_delta_changeset;
|
||||
Delta<int64_t> m_delta_uid;
|
||||
Delta<uint32_t> m_delta_user_sid;
|
||||
|
||||
bool debug;
|
||||
|
||||
bool has_debug_level(int) {
|
||||
return false;
|
||||
}
|
||||
|
||||
///// Blob writing /////
|
||||
|
||||
/**
|
||||
* Before a PrimitiveBlock gets serialized, all interim StringTable-ids needs to be
|
||||
* mapped to the associated real StringTable ids. This is done in this function.
|
||||
*
|
||||
* This function needs to know about the concrete structure of all item types to find
|
||||
* all occurrences of string-ids.
|
||||
*/
|
||||
void map_string_ids() {
|
||||
// test, if the node-block has been allocated
|
||||
if (pbf_nodes) {
|
||||
// iterate over all nodes, passing them to the map_common_string_ids function
|
||||
for (int i=0, l=pbf_nodes->nodes_size(); i<l; ++i) {
|
||||
map_common_string_ids(pbf_nodes->mutable_nodes(i));
|
||||
}
|
||||
|
||||
// test, if the node-block has a densenodes structure
|
||||
if (pbf_nodes->has_dense()) {
|
||||
// get a pointer to the densenodes structure
|
||||
OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
|
||||
|
||||
// in the densenodes structure keys and vals are encoded in an intermixed
|
||||
// array, individual nodes are seperated by a value of 0 (0 in the StringTable
|
||||
// is always unused). String-ids of 0 are thus kept alone.
|
||||
for (int i=0, l=dense->keys_vals_size(); i<l; ++i) {
|
||||
// map interim string-ids > 0 to real string ids
|
||||
auto sid = dense->keys_vals(i);
|
||||
assert(sid >= 0);
|
||||
assert(sid < std::numeric_limits<osmium::io::detail::StringTable::string_id_type>::max());
|
||||
if (sid > 0) {
|
||||
dense->set_keys_vals(i, string_table.map_string_id(static_cast<osmium::io::detail::StringTable::string_id_type>(sid)));
|
||||
}
|
||||
}
|
||||
|
||||
// test if the densenodes block has meta infos
|
||||
if (dense->has_denseinfo()) {
|
||||
// get a pointer to the denseinfo structure
|
||||
OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
|
||||
|
||||
// iterate over all username string-ids
|
||||
for (int i=0, l=denseinfo->user_sid_size(); i<l; ++i) {
|
||||
// map interim string-ids > 0 to real string ids
|
||||
auto usid = denseinfo->user_sid(i);
|
||||
assert(usid < std::numeric_limits<osmium::io::detail::StringTable::string_id_type>::max());
|
||||
auto user_sid = string_table.map_string_id(static_cast<osmium::io::detail::StringTable::string_id_type>(usid));
|
||||
|
||||
// delta encode the string-id
|
||||
denseinfo->set_user_sid(i, m_delta_user_sid.update(user_sid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test, if the ways-block has been allocated
|
||||
if (pbf_ways) {
|
||||
// iterate over all ways, passing them to the map_common_string_ids function
|
||||
for (int i=0, l=pbf_ways->ways_size(); i<l; ++i) {
|
||||
map_common_string_ids(pbf_ways->mutable_ways(i));
|
||||
}
|
||||
}
|
||||
|
||||
// test, if the relations-block has been allocated
|
||||
if (pbf_relations) {
|
||||
// iterate over all relations
|
||||
for (int i=0, l=pbf_relations->relations_size(); i<l; ++i) {
|
||||
// get a pointer to the relation
|
||||
OSMPBF::Relation* relation = pbf_relations->mutable_relations(i);
|
||||
|
||||
// pass them to the map_common_string_ids function
|
||||
map_common_string_ids(relation);
|
||||
|
||||
// iterate over all relation members, mapping the interim string-ids
|
||||
// of the role to real string ids
|
||||
for (int mi=0, ml=relation->roles_sid_size(); mi<ml; ++mi) {
|
||||
relation->set_roles_sid(mi, string_table.map_string_id(relation->roles_sid(mi)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a helper function used in map_string_ids to map common interim string-ids of the
|
||||
* user name and all tags to real string ids.
|
||||
*
|
||||
* TPBFObject is either OSMPBF::Node, OSMPBF::Way or OSMPBF::Relation.
|
||||
*/
|
||||
template <class TPBFObject>
|
||||
void map_common_string_ids(TPBFObject* in) {
|
||||
// if the object has meta-info attached
|
||||
if (in->has_info()) {
|
||||
// map the interim-id of the user name to a real id
|
||||
OSMPBF::Info* info = in->mutable_info();
|
||||
info->set_user_sid(string_table.map_string_id(info->user_sid()));
|
||||
}
|
||||
|
||||
// iterate over all tags and map the interim-ids of the key and the value to real ids
|
||||
for (int i=0, l=in->keys_size(); i<l; ++i) {
|
||||
in->set_keys(i, string_table.map_string_id(in->keys(i)));
|
||||
in->set_vals(i, string_table.map_string_id(in->vals(i)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///// MetaData helper /////
|
||||
|
||||
/**
|
||||
* convert a double lat or lon value to an int, respecting the current blocks granularity
|
||||
*/
|
||||
int64_t lonlat2int(double lonlat) {
|
||||
return round(lonlat * OSMPBF::lonlat_resolution / location_granularity());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a timestamp to an int, respecting the current blocks granularity
|
||||
*/
|
||||
int64_t timestamp2int(time_t timestamp) {
|
||||
return round(timestamp * (static_cast<double>(1000) / date_granularity()));
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function used in the write()-calls to apply common information from an osmium-object
|
||||
* onto a pbf-object.
|
||||
*
|
||||
* TPBFObject is either OSMPBF::Node, OSMPBF::Way or OSMPBF::Relation.
|
||||
*/
|
||||
template <class TPBFObject>
|
||||
void apply_common_info(const osmium::OSMObject& in, TPBFObject* out) {
|
||||
// set the object-id
|
||||
out->set_id(in.id());
|
||||
|
||||
// iterate over all tags and set the keys and vals, recording the strings in the
|
||||
// interim StringTable and storing the interim ids
|
||||
for (const auto& tag : in.tags()) {
|
||||
out->add_keys(string_table.record_string(tag.key()));
|
||||
out->add_vals(string_table.record_string(tag.value()));
|
||||
}
|
||||
|
||||
if (m_should_add_metadata) {
|
||||
// add an info-section to the pbf object and set the meta-info on it
|
||||
OSMPBF::Info* out_info = out->mutable_info();
|
||||
if (m_add_visible) {
|
||||
out_info->set_visible(in.visible());
|
||||
}
|
||||
out_info->set_version(static_cast<::google::protobuf::int32>(in.version()));
|
||||
out_info->set_timestamp(timestamp2int(in.timestamp()));
|
||||
out_info->set_changeset(in.changeset());
|
||||
out_info->set_uid(static_cast<::google::protobuf::int32>(in.uid()));
|
||||
out_info->set_user_sid(string_table.record_string(in.user()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///// High-Level Block writing /////
|
||||
|
||||
/**
|
||||
* store the current pbf_header_block into a Blob and clear this struct afterwards.
|
||||
*/
|
||||
void store_header_block() {
|
||||
if (debug && has_debug_level(1)) {
|
||||
std::cerr << "storing header block" << std::endl;
|
||||
}
|
||||
|
||||
std::promise<std::string> promise;
|
||||
m_output_queue.push(promise.get_future());
|
||||
promise.set_value(serialize_blob("OSMHeader", pbf_header_block, m_use_compression));
|
||||
|
||||
pbf_header_block.Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* store the interim StringTable to the current pbf_primitive_block, map all interim string ids
|
||||
* to real StringTable ids and then store the current pbf_primitive_block into a Blob and clear
|
||||
* this struct and all related pointers and maps afterwards.
|
||||
*/
|
||||
void store_primitive_block() {
|
||||
if (debug && has_debug_level(1)) {
|
||||
std::cerr << "storing primitive block with " << primitive_block_contents << " items" << std::endl;
|
||||
}
|
||||
|
||||
// set the granularity
|
||||
pbf_primitive_block.set_granularity(location_granularity());
|
||||
pbf_primitive_block.set_date_granularity(date_granularity());
|
||||
|
||||
// store the interim StringTable into the protobuf object
|
||||
string_table.store_stringtable(pbf_primitive_block.mutable_stringtable());
|
||||
|
||||
// map all interim string ids to real ids
|
||||
map_string_ids();
|
||||
|
||||
std::promise<std::string> promise;
|
||||
m_output_queue.push(promise.get_future());
|
||||
promise.set_value(serialize_blob("OSMData", pbf_primitive_block, m_use_compression));
|
||||
while (m_output_queue.size() > 10) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // XXX
|
||||
}
|
||||
|
||||
// clear the PrimitiveBlock struct
|
||||
pbf_primitive_block.Clear();
|
||||
|
||||
// clear the interim StringTable and its id map
|
||||
string_table.clear();
|
||||
|
||||
// reset the delta variables
|
||||
m_delta_id.clear();
|
||||
m_delta_lat.clear();
|
||||
m_delta_lon.clear();
|
||||
m_delta_timestamp.clear();
|
||||
m_delta_changeset.clear();
|
||||
m_delta_uid.clear();
|
||||
m_delta_user_sid.clear();
|
||||
|
||||
// reset the contents-counter to zero
|
||||
primitive_block_contents = 0;
|
||||
primitive_block_size = 0;
|
||||
|
||||
// reset the node/way/relation pointers to nullptr
|
||||
pbf_nodes = nullptr;
|
||||
pbf_ways = nullptr;
|
||||
pbf_relations = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* this little function checks primitive_block_contents counter against its maximum and calls
|
||||
* store_primitive_block to flush the block to the disk when it's reached. It's also responsible
|
||||
* for increasing this counter.
|
||||
*
|
||||
* this function also checks the estimated size of the current block and calls store_primitive_block
|
||||
* when the estimated size reaches buffer_fill_percent of the maximum uncompressed blob size.
|
||||
*/
|
||||
void check_block_contents_counter() {
|
||||
if (primitive_block_contents >= max_block_contents) {
|
||||
store_primitive_block();
|
||||
} else if (primitive_block_size > (static_cast<uint32_t>(OSMPBF::max_uncompressed_blob_size) * buffer_fill_percent / 100)) {
|
||||
if (debug && has_debug_level(1)) {
|
||||
std::cerr << "storing primitive_block with only " << primitive_block_contents << " items, because its ByteSize (" << primitive_block_size << ") reached " <<
|
||||
(static_cast<float>(primitive_block_size) / static_cast<float>(OSMPBF::max_uncompressed_blob_size) * 100.0) << "% of the maximum blob-size" << std::endl;
|
||||
}
|
||||
|
||||
store_primitive_block();
|
||||
}
|
||||
|
||||
++primitive_block_contents;
|
||||
}
|
||||
|
||||
|
||||
///// Block content writing /////
|
||||
|
||||
/**
|
||||
* Add a node to the block.
|
||||
*
|
||||
* @param node The node to add.
|
||||
*/
|
||||
void write_node(const osmium::Node& node) {
|
||||
// add a way to the group
|
||||
OSMPBF::Node* pbf_node = pbf_nodes->add_nodes();
|
||||
|
||||
// copy the common meta-info from the osmium-object to the pbf-object
|
||||
apply_common_info(node, pbf_node);
|
||||
|
||||
// modify lat & lon to integers, respecting the block's granularity and copy
|
||||
// the ints to the pbf-object
|
||||
pbf_node->set_lon(lonlat2int(node.location().lon_without_check()));
|
||||
pbf_node->set_lat(lonlat2int(node.location().lat_without_check()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a node to the block using DenseNodes.
|
||||
*
|
||||
* @param node The node to add.
|
||||
*/
|
||||
void write_dense_node(const osmium::Node& node) {
|
||||
// add a DenseNodes-Section to the PrimitiveGroup
|
||||
OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
|
||||
|
||||
// copy the id, delta encoded
|
||||
dense->add_id(m_delta_id.update(node.id()));
|
||||
|
||||
// copy the longitude, delta encoded
|
||||
dense->add_lon(m_delta_lon.update(lonlat2int(node.location().lon_without_check())));
|
||||
|
||||
// copy the latitude, delta encoded
|
||||
dense->add_lat(m_delta_lat.update(lonlat2int(node.location().lat_without_check())));
|
||||
|
||||
// in the densenodes structure keys and vals are encoded in an intermixed
|
||||
// array, individual nodes are seperated by a value of 0 (0 in the StringTable
|
||||
// is always unused)
|
||||
// so for three nodes the keys_vals array may look like this: 3 5 2 1 0 0 8 5
|
||||
// the first node has two tags (3=>5 and 2=>1), the second node does not
|
||||
// have any tags and the third node has a single tag (8=>5)
|
||||
for (const auto& tag : node.tags()) {
|
||||
dense->add_keys_vals(string_table.record_string(tag.key()));
|
||||
dense->add_keys_vals(string_table.record_string(tag.value()));
|
||||
}
|
||||
dense->add_keys_vals(0);
|
||||
|
||||
if (m_should_add_metadata) {
|
||||
// add a DenseInfo-Section to the PrimitiveGroup
|
||||
OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
|
||||
|
||||
denseinfo->add_version(static_cast<::google::protobuf::int32>(node.version()));
|
||||
|
||||
if (m_add_visible) {
|
||||
denseinfo->add_visible(node.visible());
|
||||
}
|
||||
|
||||
// copy the timestamp, delta encoded
|
||||
denseinfo->add_timestamp(m_delta_timestamp.update(timestamp2int(node.timestamp())));
|
||||
|
||||
// copy the changeset, delta encoded
|
||||
denseinfo->add_changeset(m_delta_changeset.update(node.changeset()));
|
||||
|
||||
// copy the user id, delta encoded
|
||||
denseinfo->add_uid(m_delta_uid.update(node.uid()));
|
||||
|
||||
// record the user-name to the interim stringtable and copy the
|
||||
// interim string-id to the pbf-object
|
||||
denseinfo->add_user_sid(string_table.record_string(node.user()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a way to the block.
|
||||
*
|
||||
* @param way The way to add.
|
||||
*/
|
||||
void write_way(const osmium::Way& way) {
|
||||
// add a way to the group
|
||||
OSMPBF::Way* pbf_way = pbf_ways->add_ways();
|
||||
|
||||
// copy the common meta-info from the osmium-object to the pbf-object
|
||||
apply_common_info(way, pbf_way);
|
||||
|
||||
// last way-node-id used for delta-encoding
|
||||
Delta<int64_t> delta_id;
|
||||
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
// copy the way-node-id, delta encoded
|
||||
pbf_way->add_refs(delta_id.update(node_ref.ref()));
|
||||
}
|
||||
|
||||
// count up blob size by the size of the Way
|
||||
primitive_block_size += pbf_way->ByteSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a relation to the block.
|
||||
*
|
||||
* @param relation The relation to add.
|
||||
*/
|
||||
void write_relation(const osmium::Relation& relation) {
|
||||
// add a relation to the group
|
||||
OSMPBF::Relation* pbf_relation = pbf_relations->add_relations();
|
||||
|
||||
// copy the common meta-info from the osmium-object to the pbf-object
|
||||
apply_common_info(relation, pbf_relation);
|
||||
|
||||
Delta<int64_t> delta_id;
|
||||
|
||||
for (const auto& member : relation.members()) {
|
||||
// record the relation-member role to the interim stringtable and copy the
|
||||
// interim string-id to the pbf-object
|
||||
pbf_relation->add_roles_sid(string_table.record_string(member.role()));
|
||||
|
||||
// copy the relation-member-id, delta encoded
|
||||
pbf_relation->add_memids(delta_id.update(member.ref()));
|
||||
|
||||
// copy the relation-member-type, mapped to the OSMPBF enum
|
||||
pbf_relation->add_types(item_type_to_osmpbf_membertype(member.type()));
|
||||
}
|
||||
|
||||
// count up blob size by the size of the Relation
|
||||
primitive_block_size += pbf_relation->ByteSize();
|
||||
}
|
||||
|
||||
// objects of this class can't be copied
|
||||
PBFOutputFormat(const PBFOutputFormat&) = delete;
|
||||
PBFOutputFormat& operator=(const PBFOutputFormat&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create PBFOutputFormat object from File.
|
||||
*/
|
||||
explicit PBFOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
|
||||
OutputFormat(file, output_queue),
|
||||
pbf_header_block(),
|
||||
pbf_primitive_block(),
|
||||
pbf_nodes(nullptr),
|
||||
pbf_ways(nullptr),
|
||||
pbf_relations(nullptr),
|
||||
m_location_granularity(pbf_primitive_block.granularity()),
|
||||
m_date_granularity(pbf_primitive_block.date_granularity()),
|
||||
m_add_visible(file.has_multiple_object_versions()),
|
||||
primitive_block_contents(0),
|
||||
primitive_block_size(0),
|
||||
string_table(),
|
||||
m_delta_id(),
|
||||
m_delta_lat(),
|
||||
m_delta_lon(),
|
||||
m_delta_timestamp(),
|
||||
m_delta_changeset(),
|
||||
m_delta_uid(),
|
||||
m_delta_user_sid(),
|
||||
debug(true) {
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
if (file.get("pbf_dense_nodes") == "false") {
|
||||
m_use_dense_nodes = false;
|
||||
}
|
||||
if (file.get("pbf_compression") == "none" || file.get("pbf_compression") == "false") {
|
||||
m_use_compression = false;
|
||||
}
|
||||
if (file.get("pbf_add_metadata") == "false") {
|
||||
m_should_add_metadata = false;
|
||||
}
|
||||
}
|
||||
|
||||
void write_buffer(osmium::memory::Buffer&& buffer) override final {
|
||||
osmium::apply(buffer.cbegin(), buffer.cend(), *this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getter to access the granularity
|
||||
*/
|
||||
int location_granularity() const {
|
||||
return m_location_granularity;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter to set the granularity
|
||||
*/
|
||||
PBFOutputFormat& location_granularity(int g) {
|
||||
m_location_granularity = g;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getter to access the date_granularity
|
||||
*/
|
||||
int date_granularity() const {
|
||||
return m_date_granularity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set date granularity.
|
||||
*/
|
||||
PBFOutputFormat& date_granularity(int g) {
|
||||
m_date_granularity = g;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the writing process.
|
||||
*
|
||||
* This initializes the header-block, sets the required-features and
|
||||
* the writing-program and adds the obligatory StringTable-Index 0.
|
||||
*/
|
||||
void write_header(const osmium::io::Header& header) override final {
|
||||
// add the schema version as required feature to the HeaderBlock
|
||||
pbf_header_block.add_required_features("OsmSchema-V0.6");
|
||||
|
||||
// when the densenodes-feature is used, add DenseNodes as required feature
|
||||
if (m_use_dense_nodes) {
|
||||
pbf_header_block.add_required_features("DenseNodes");
|
||||
}
|
||||
|
||||
// when the resulting file will carry history information, add
|
||||
// HistoricalInformation as required feature
|
||||
if (this->m_file.has_multiple_object_versions()) {
|
||||
pbf_header_block.add_required_features("HistoricalInformation");
|
||||
}
|
||||
|
||||
// set the writing program
|
||||
pbf_header_block.set_writingprogram(header.get("generator"));
|
||||
|
||||
if (!header.boxes().empty()) {
|
||||
OSMPBF::HeaderBBox* pbf_bbox = pbf_header_block.mutable_bbox();
|
||||
osmium::Box box = header.joined_boxes();
|
||||
pbf_bbox->set_left(static_cast<::google::protobuf::int64>(box.bottom_left().lon() * OSMPBF::lonlat_resolution));
|
||||
pbf_bbox->set_bottom(static_cast<::google::protobuf::int64>(box.bottom_left().lat() * OSMPBF::lonlat_resolution));
|
||||
pbf_bbox->set_right(static_cast<::google::protobuf::int64>(box.top_right().lon() * OSMPBF::lonlat_resolution));
|
||||
pbf_bbox->set_top(static_cast<::google::protobuf::int64>(box.top_right().lat() * OSMPBF::lonlat_resolution));
|
||||
}
|
||||
|
||||
std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
|
||||
if (!osmosis_replication_timestamp.empty()) {
|
||||
osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
|
||||
pbf_header_block.set_osmosis_replication_timestamp(ts);
|
||||
}
|
||||
|
||||
std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
|
||||
if (!osmosis_replication_sequence_number.empty()) {
|
||||
pbf_header_block.set_osmosis_replication_sequence_number(std::atoll(osmosis_replication_sequence_number.c_str()));
|
||||
}
|
||||
|
||||
std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
|
||||
if (!osmosis_replication_base_url.empty()) {
|
||||
pbf_header_block.set_osmosis_replication_base_url(osmosis_replication_base_url);
|
||||
}
|
||||
|
||||
store_header_block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a node to the pbf.
|
||||
*
|
||||
* A call to this method won't write the node to the file directly but
|
||||
* cache it for later bulk-writing. Calling final() ensures that everything
|
||||
* gets written and every file pointer is closed.
|
||||
*/
|
||||
void node(const osmium::Node& node) {
|
||||
// first of we check the contents-counter which may flush the cached nodes to
|
||||
// disk if the limit is reached. This call also increases the contents-counter
|
||||
check_block_contents_counter();
|
||||
|
||||
if (debug && has_debug_level(2)) {
|
||||
std::cerr << "node " << node.id() << " v" << node.version() << std::endl;
|
||||
}
|
||||
|
||||
// if no PrimitiveGroup for nodes has been added, add one and save the pointer
|
||||
if (!pbf_nodes) {
|
||||
pbf_nodes = pbf_primitive_block.add_primitivegroup();
|
||||
}
|
||||
|
||||
if (m_use_dense_nodes) {
|
||||
write_dense_node(node);
|
||||
} else {
|
||||
write_node(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a way to the pbf.
|
||||
*
|
||||
* A call to this method won't write the way to the file directly but
|
||||
* cache it for later bulk-writing. Calling final() ensures that everything
|
||||
* gets written and every file pointer is closed.
|
||||
*/
|
||||
void way(const osmium::Way& way) {
|
||||
// first of we check the contents-counter which may flush the cached ways to
|
||||
// disk if the limit is reached. This call also increases the contents-counter
|
||||
check_block_contents_counter();
|
||||
|
||||
// if no PrimitiveGroup for nodes has been added, add one and save the pointer
|
||||
if (!pbf_ways) {
|
||||
pbf_ways = pbf_primitive_block.add_primitivegroup();
|
||||
}
|
||||
|
||||
write_way(way);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a relation to the pbf.
|
||||
*
|
||||
* A call to this method won't write the way to the file directly but
|
||||
* cache it for later bulk-writing. Calling final() ensures that everything
|
||||
* gets written and every file pointer is closed.
|
||||
*/
|
||||
void relation(const osmium::Relation& relation) {
|
||||
// first of we check the contents-counter which may flush the cached relations to
|
||||
// disk if the limit is reached. This call also increases the contents-counter
|
||||
check_block_contents_counter();
|
||||
|
||||
// if no PrimitiveGroup for relations has been added, add one and save the pointer
|
||||
if (!pbf_relations) {
|
||||
pbf_relations = pbf_primitive_block.add_primitivegroup();
|
||||
}
|
||||
|
||||
write_relation(relation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the writing process, flush any open primitive blocks to the file and
|
||||
* close the file.
|
||||
*/
|
||||
void close() override final {
|
||||
if (debug && has_debug_level(1)) {
|
||||
std::cerr << "finishing" << std::endl;
|
||||
}
|
||||
|
||||
// if the current block contains any elements, flush it to the protobuf
|
||||
if (primitive_block_contents > 0) {
|
||||
store_primitive_block();
|
||||
}
|
||||
|
||||
std::promise<std::string> promise;
|
||||
m_output_queue.push(promise.get_future());
|
||||
promise.set_value(std::string());
|
||||
}
|
||||
|
||||
}; // class PBFOutputFormat
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf,
|
||||
[](const osmium::io::File& file, data_queue_type& output_queue) {
|
||||
return new osmium::io::detail::PBFOutputFormat(file, output_queue);
|
||||
});
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
|
||||
-196
@@ -1,196 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
|
||||
#define OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <osmpbf/osmpbf.h>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* StringTable management for PBF writer
|
||||
*
|
||||
* All strings are stored as indexes to rows in a StringTable. The StringTable contains
|
||||
* one row for each used string, so strings that are used multiple times need to be
|
||||
* stored only once. The StringTable is sorted by usage-count, so the most often used
|
||||
* string is stored at index 1.
|
||||
*/
|
||||
class StringTable {
|
||||
|
||||
public:
|
||||
|
||||
/// type for string IDs (interim and final)
|
||||
typedef uint16_t string_id_type;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* this is the struct used to build the StringTable. It is stored as
|
||||
* the value-part in the strings-map.
|
||||
*
|
||||
* when a new string is added to the map, its count is set to 0 and
|
||||
* the interim_id is set to the current size of the map. This interim_id
|
||||
* is then stored into the pbf-objects.
|
||||
*
|
||||
* before the PrimitiveBlock is serialized, the map is sorted by count
|
||||
* and stored into the pbf-StringTable. Afterwards the interim-ids are
|
||||
* mapped to the "real" id in the StringTable.
|
||||
*
|
||||
* this way often used strings get lower ids in the StringTable. As the
|
||||
* protobuf-serializer stores numbers in variable bit-lengths, lower
|
||||
* IDs means less used space in the resulting file.
|
||||
*/
|
||||
struct string_info {
|
||||
/// number of occurrences of this string
|
||||
uint16_t count;
|
||||
|
||||
/// an intermediate-id
|
||||
string_id_type interim_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interim StringTable, storing all strings that should be written to
|
||||
* the StringTable once the block is written to disk.
|
||||
*/
|
||||
typedef std::map<std::string, string_info> string2string_info_type;
|
||||
string2string_info_type m_strings {};
|
||||
|
||||
/**
|
||||
* This vector is used to map the interim IDs to real StringTable IDs after
|
||||
* writing all strings to the StringTable.
|
||||
*/
|
||||
typedef std::vector<string_id_type> interim_id2id_type;
|
||||
interim_id2id_type m_id2id_map {};
|
||||
|
||||
size_t m_size = 0;
|
||||
|
||||
public:
|
||||
|
||||
StringTable() {
|
||||
}
|
||||
|
||||
friend bool operator<(const string_info& lhs, const string_info& rhs) {
|
||||
return lhs.count > rhs.count;
|
||||
}
|
||||
|
||||
/**
|
||||
* record a string in the interim StringTable if it's missing, otherwise just increase its counter,
|
||||
* return the interim-id assigned to the string.
|
||||
*/
|
||||
string_id_type record_string(const std::string& string) {
|
||||
string_info& info = m_strings[string];
|
||||
if (info.interim_id == 0) {
|
||||
++m_size;
|
||||
assert(m_size < std::numeric_limits<string_id_type>::max());
|
||||
info.interim_id = static_cast<string_id_type>(m_size);
|
||||
} else {
|
||||
info.count++;
|
||||
}
|
||||
return info.interim_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the interim StringTable and store it to the real protobuf StringTable.
|
||||
* while storing to the real table, this function fills the id2id_map with
|
||||
* pairs, mapping the interim-ids to final and real StringTable ids.
|
||||
*
|
||||
* Note that the m_strings table is a std::map and as such is sorted lexicographically.
|
||||
* When the transformation into the sortedby multimap is done, it gets sorted by
|
||||
* the count. The end result (at least with the glibc standard container/algorithm
|
||||
* implementation) is that the string table is sorted first by reverse count (ie descending)
|
||||
* and then by reverse lexicographic order.
|
||||
*/
|
||||
void store_stringtable(OSMPBF::StringTable* st) {
|
||||
// add empty StringTable entry at index 0
|
||||
// StringTable index 0 is reserved as delimiter in the densenodes key/value list
|
||||
// this line also ensures that there's always a valid StringTable
|
||||
st->add_s("");
|
||||
|
||||
std::multimap<string_info, std::string> sortedbycount;
|
||||
|
||||
m_id2id_map.resize(m_size+1);
|
||||
|
||||
std::transform(m_strings.begin(), m_strings.end(),
|
||||
std::inserter(sortedbycount, sortedbycount.begin()),
|
||||
[](const std::pair<std::string, string_info>& p) {
|
||||
return std::pair<string_info, std::string>(p.second, p.first);
|
||||
});
|
||||
|
||||
string_id_type n=0;
|
||||
|
||||
for (const auto& mapping : sortedbycount) {
|
||||
// add the string of the current item to the pbf StringTable
|
||||
st->add_s(mapping.second);
|
||||
|
||||
// store the mapping from the interim-id to the real id
|
||||
m_id2id_map[mapping.first.interim_id] = ++n;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map from an interim ID to a real string ID.
|
||||
*/
|
||||
string_id_type map_string_id(const string_id_type interim_id) const {
|
||||
return m_id2id_map[interim_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the stringtable, preparing for the next block.
|
||||
*/
|
||||
void clear() {
|
||||
m_strings.clear();
|
||||
m_id2id_map.clear();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
}; // class StringTable
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_READ_THREAD_HPP
|
||||
#define OSMIUM_IO_DETAIL_READ_THREAD_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/thread/name.hpp>
|
||||
#include <osmium/thread/queue.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class ReadThread {
|
||||
|
||||
osmium::thread::Queue<std::string>& m_queue;
|
||||
osmium::io::Decompressor* m_decompressor;
|
||||
|
||||
// If this is set in the main thread, we have to wrap up at the
|
||||
// next possible moment.
|
||||
std::atomic<bool>& m_done;
|
||||
|
||||
public:
|
||||
|
||||
explicit ReadThread(osmium::thread::Queue<std::string>& queue, osmium::io::Decompressor* decompressor, std::atomic<bool>& done) :
|
||||
m_queue(queue),
|
||||
m_decompressor(decompressor),
|
||||
m_done(done) {
|
||||
}
|
||||
|
||||
void operator()() {
|
||||
osmium::thread::set_thread_name("_osmium_input");
|
||||
|
||||
try {
|
||||
while (!m_done) {
|
||||
std::string data {m_decompressor->read()};
|
||||
if (data.empty()) {
|
||||
m_done = true;
|
||||
}
|
||||
m_queue.push(std::move(data));
|
||||
while (m_queue.size() > 10) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
m_decompressor->close();
|
||||
} catch (...) {
|
||||
// If there is an exception in this thread, we make sure
|
||||
// to push an empty string onto the queue to signal the
|
||||
// end-of-data to the reading thread so that it will not
|
||||
// hang. Then we re-throw the exception.
|
||||
m_queue.push(std::string());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
}; // class ReadThread
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_READ_THREAD_HPP
|
||||
-165
@@ -1,165 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_READ_WRITE_HPP
|
||||
#define OSMIUM_IO_DETAIL_READ_WRITE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
//#include <sys/stat.h>
|
||||
//#include <sys/types.h>
|
||||
#include <system_error>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <osmium/io/overwrite.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
/**
|
||||
* @brief Namespace for Osmium internal use
|
||||
*/
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Open file for writing. If the file exists, it is truncated, if
|
||||
* not, it is created. If the file name is empty or "-", no file
|
||||
* is open and the stdout file descriptor (1) is returned.
|
||||
*
|
||||
* @param filename Name of file to be opened.
|
||||
* @param allow_overwrite If the file exists, should it be overwritten?
|
||||
* @return File descriptor of open file.
|
||||
* @throws system_error if the file can't be opened.
|
||||
*/
|
||||
inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) {
|
||||
if (filename == "" || filename == "-") {
|
||||
return 1; // stdout
|
||||
} else {
|
||||
int flags = O_WRONLY | O_CREAT;
|
||||
if (allow_overwrite == osmium::io::overwrite::allow) {
|
||||
flags |= O_TRUNC;
|
||||
} else {
|
||||
flags |= O_EXCL;
|
||||
}
|
||||
#ifdef WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
int fd = ::open(filename.c_str(), flags, 0666);
|
||||
if (fd < 0) {
|
||||
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open file for reading. If the file name is empty or "-", no file
|
||||
* is open and the stdin file descriptor (0) is returned.
|
||||
*
|
||||
* @return File descriptor of open file.
|
||||
* @throws system_error if the file can't be opened.
|
||||
*/
|
||||
inline int open_for_reading(const std::string& filename) {
|
||||
if (filename == "" || filename == "-") {
|
||||
return 0; // stdin
|
||||
} else {
|
||||
int flags = O_RDONLY;
|
||||
#ifdef WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
int fd = ::open(filename.c_str(), flags);
|
||||
if (fd < 0) {
|
||||
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given number of bytes into the input buffer.
|
||||
* This is basically just a wrapper around read(2).
|
||||
*
|
||||
* @param fd File descriptor.
|
||||
* @param input_buffer Buffer with data of at least size.
|
||||
* @param size Number of bytes to be read.
|
||||
* @return True when read was successful, false on EOF.
|
||||
* @exception std::system_error On error.
|
||||
*/
|
||||
inline bool reliable_read(const int fd, unsigned char* input_buffer, const size_t size) {
|
||||
size_t offset = 0;
|
||||
while (offset < size) {
|
||||
ssize_t length = ::read(fd, input_buffer + offset, size - offset);
|
||||
if (length < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "Read failed");
|
||||
}
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
offset += static_cast<size_t>(length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given number of bytes from the output_buffer to the file descriptor.
|
||||
* This is just a wrapper around write(2).
|
||||
*
|
||||
* @param fd File descriptor.
|
||||
* @param output_buffer Buffer where data is written. Must be at least size bytes long.
|
||||
* @param size Number of bytes to be read.
|
||||
* @exception std::system_error On error.
|
||||
*/
|
||||
inline void reliable_write(const int fd, const unsigned char* output_buffer, const size_t size) {
|
||||
size_t offset = 0;
|
||||
do {
|
||||
ssize_t length = ::write(fd, output_buffer + offset, size - offset);
|
||||
if (length < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "Write failed");
|
||||
}
|
||||
offset += static_cast<size_t>(length);
|
||||
} while (offset < size);
|
||||
}
|
||||
|
||||
inline void reliable_write(const int fd, const char* output_buffer, const size_t size) {
|
||||
reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_READ_WRITE_HPP
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
|
||||
#define OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <future>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/thread/name.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class WriteThread {
|
||||
|
||||
typedef osmium::io::detail::data_queue_type data_queue_type;
|
||||
|
||||
data_queue_type& m_input_queue;
|
||||
osmium::io::Compressor* m_compressor;
|
||||
|
||||
public:
|
||||
|
||||
explicit WriteThread(data_queue_type& input_queue, osmium::io::Compressor* compressor) :
|
||||
m_input_queue(input_queue),
|
||||
m_compressor(compressor) {
|
||||
}
|
||||
|
||||
void operator()() {
|
||||
osmium::thread::set_thread_name("_osmium_output");
|
||||
|
||||
std::future<std::string> data_future;
|
||||
std::string data;
|
||||
do {
|
||||
m_input_queue.wait_and_pop(data_future);
|
||||
data = data_future.get();
|
||||
m_compressor->write(data);
|
||||
} while (!data.empty());
|
||||
|
||||
m_compressor->close();
|
||||
}
|
||||
|
||||
}; // class WriteThread
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
|
||||
-640
@@ -1,640 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#define OSMIUM_LINK_WITH_LIBS_EXPAT -lexpat
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <ratio>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <expat.h>
|
||||
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/thread/queue.hpp>
|
||||
#include <osmium/thread/checked_task.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
struct xml_error : public io_error {
|
||||
|
||||
unsigned long line;
|
||||
unsigned long column;
|
||||
XML_Error error_code;
|
||||
std::string error_string;
|
||||
|
||||
xml_error(XML_Parser parser) :
|
||||
io_error(std::string("XML parsing error at line ")
|
||||
+ std::to_string(XML_GetCurrentLineNumber(parser))
|
||||
+ ", column "
|
||||
+ std::to_string(XML_GetCurrentColumnNumber(parser))
|
||||
+ ": "
|
||||
+ XML_ErrorString(XML_GetErrorCode(parser))),
|
||||
line(XML_GetCurrentLineNumber(parser)),
|
||||
column(XML_GetCurrentColumnNumber(parser)),
|
||||
error_code(XML_GetErrorCode(parser)),
|
||||
error_string(XML_ErrorString(error_code)) {
|
||||
}
|
||||
|
||||
}; // struct xml_error
|
||||
|
||||
struct format_version_error : public io_error {
|
||||
|
||||
std::string version;
|
||||
|
||||
explicit format_version_error() :
|
||||
io_error("Can not read file without version (missing version attribute on osm element)."),
|
||||
version() {
|
||||
}
|
||||
|
||||
explicit format_version_error(const char* v) :
|
||||
io_error(std::string("Can not read file with version ") + v),
|
||||
version(v) {
|
||||
}
|
||||
|
||||
}; // struct format_version_error
|
||||
|
||||
namespace io {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Once the header is fully parsed this exception will be thrown if
|
||||
* the caller is not interested in anything else except the header.
|
||||
* It will break off the parsing at this point.
|
||||
*/
|
||||
class ParserIsDone : std::exception {
|
||||
};
|
||||
|
||||
class XMLParser {
|
||||
|
||||
static constexpr int buffer_size = 10 * 1000 * 1000;
|
||||
|
||||
enum class context {
|
||||
root,
|
||||
top,
|
||||
node,
|
||||
way,
|
||||
relation,
|
||||
changeset,
|
||||
ignored_node,
|
||||
ignored_way,
|
||||
ignored_relation,
|
||||
ignored_changeset,
|
||||
in_object
|
||||
};
|
||||
|
||||
context m_context;
|
||||
context m_last_context;
|
||||
|
||||
/**
|
||||
* This is used only for change files which contain create, modify,
|
||||
* and delete sections.
|
||||
*/
|
||||
bool m_in_delete_section;
|
||||
|
||||
osmium::io::Header m_header;
|
||||
|
||||
osmium::memory::Buffer m_buffer;
|
||||
|
||||
std::unique_ptr<osmium::builder::NodeBuilder> m_node_builder;
|
||||
std::unique_ptr<osmium::builder::WayBuilder> m_way_builder;
|
||||
std::unique_ptr<osmium::builder::RelationBuilder> m_relation_builder;
|
||||
std::unique_ptr<osmium::builder::ChangesetBuilder> m_changeset_builder;
|
||||
|
||||
std::unique_ptr<osmium::builder::TagListBuilder> m_tl_builder;
|
||||
std::unique_ptr<osmium::builder::WayNodeListBuilder> m_wnl_builder;
|
||||
std::unique_ptr<osmium::builder::RelationMemberListBuilder> m_rml_builder;
|
||||
|
||||
osmium::thread::Queue<std::string>& m_input_queue;
|
||||
osmium::thread::Queue<osmium::memory::Buffer>& m_queue;
|
||||
std::promise<osmium::io::Header>& m_header_promise;
|
||||
|
||||
bool m_promise_fulfilled;
|
||||
|
||||
osmium::osm_entity_bits::type m_read_types;
|
||||
|
||||
size_t m_max_queue_size;
|
||||
|
||||
std::atomic<bool>& m_done;
|
||||
|
||||
public:
|
||||
|
||||
explicit XMLParser(osmium::thread::Queue<std::string>& input_queue, osmium::thread::Queue<osmium::memory::Buffer>& queue, std::promise<osmium::io::Header>& header_promise, osmium::osm_entity_bits::type read_types, std::atomic<bool>& done) :
|
||||
m_context(context::root),
|
||||
m_last_context(context::root),
|
||||
m_in_delete_section(false),
|
||||
m_header(),
|
||||
m_buffer(buffer_size),
|
||||
m_node_builder(),
|
||||
m_way_builder(),
|
||||
m_relation_builder(),
|
||||
m_changeset_builder(),
|
||||
m_tl_builder(),
|
||||
m_wnl_builder(),
|
||||
m_rml_builder(),
|
||||
m_input_queue(input_queue),
|
||||
m_queue(queue),
|
||||
m_header_promise(header_promise),
|
||||
m_promise_fulfilled(false),
|
||||
m_read_types(read_types),
|
||||
m_max_queue_size(100),
|
||||
m_done(done) {
|
||||
}
|
||||
|
||||
void operator()() {
|
||||
XML_Parser parser = XML_ParserCreate(nullptr);
|
||||
if (!parser) {
|
||||
throw osmium::io_error("Internal error: Can not create parser");
|
||||
}
|
||||
|
||||
XML_SetUserData(parser, this);
|
||||
|
||||
XML_SetElementHandler(parser, start_element_wrapper, end_element_wrapper);
|
||||
|
||||
try {
|
||||
int done;
|
||||
do {
|
||||
std::string data;
|
||||
m_input_queue.wait_and_pop(data);
|
||||
done = data.empty();
|
||||
try {
|
||||
if (XML_Parse(parser, data.data(), data.size(), done) == XML_STATUS_ERROR) {
|
||||
throw osmium::xml_error(parser);
|
||||
}
|
||||
} catch (ParserIsDone&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
|
||||
if (!m_promise_fulfilled) {
|
||||
m_promise_fulfilled = true;
|
||||
m_header_promise.set_value(m_header);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
} while (!done && !m_done);
|
||||
header_is_done(); // make sure we'll always fulfill the promise
|
||||
if (m_buffer.committed() > 0) {
|
||||
m_queue.push(std::move(m_buffer));
|
||||
}
|
||||
m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
|
||||
} catch (ParserIsDone&) {
|
||||
// intentionally left blank
|
||||
}
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void XMLCALL start_element_wrapper(void* data, const XML_Char* element, const XML_Char** attrs) {
|
||||
static_cast<XMLParser*>(data)->start_element(element, attrs);
|
||||
}
|
||||
|
||||
static void XMLCALL end_element_wrapper(void* data, const XML_Char* element) {
|
||||
static_cast<XMLParser*>(data)->end_element(element);
|
||||
}
|
||||
|
||||
const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) {
|
||||
static const char* empty = "";
|
||||
const char* user = empty;
|
||||
|
||||
if (m_in_delete_section) {
|
||||
object.visible(false);
|
||||
}
|
||||
for (int count = 0; attrs[count]; count += 2) {
|
||||
if (!strcmp(attrs[count], "lon")) {
|
||||
static_cast<osmium::Node&>(object).location().lon(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
|
||||
} else if (!strcmp(attrs[count], "lat")) {
|
||||
static_cast<osmium::Node&>(object).location().lat(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
|
||||
} else if (!strcmp(attrs[count], "user")) {
|
||||
user = attrs[count+1];
|
||||
} else {
|
||||
object.set_attribute(attrs[count], attrs[count+1]);
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) {
|
||||
static const char* empty = "";
|
||||
const char* user = empty;
|
||||
osmium::Changeset& new_changeset = builder->object();
|
||||
|
||||
osmium::Location min {};
|
||||
osmium::Location max {};
|
||||
for (int count = 0; attrs[count]; count += 2) {
|
||||
if (!strcmp(attrs[count], "min_lon")) {
|
||||
min.lon(atof(attrs[count+1]));
|
||||
} else if (!strcmp(attrs[count], "min_lat")) {
|
||||
min.lat(atof(attrs[count+1]));
|
||||
} else if (!strcmp(attrs[count], "max_lon")) {
|
||||
max.lon(atof(attrs[count+1]));
|
||||
} else if (!strcmp(attrs[count], "max_lat")) {
|
||||
max.lat(atof(attrs[count+1]));
|
||||
} else if (!strcmp(attrs[count], "user")) {
|
||||
user = attrs[count+1];
|
||||
} else {
|
||||
new_changeset.set_attribute(attrs[count], attrs[count+1]);
|
||||
}
|
||||
}
|
||||
|
||||
new_changeset.bounds().extend(min);
|
||||
new_changeset.bounds().extend(max);
|
||||
|
||||
builder->add_user(user);
|
||||
}
|
||||
|
||||
void check_tag(osmium::builder::Builder* builder, const XML_Char* element, const XML_Char** attrs) {
|
||||
if (!strcmp(element, "tag")) {
|
||||
m_wnl_builder.reset();
|
||||
m_rml_builder.reset();
|
||||
|
||||
const char* key = "";
|
||||
const char* value = "";
|
||||
for (int count = 0; attrs[count]; count += 2) {
|
||||
if (attrs[count][0] == 'k' && attrs[count][1] == 0) {
|
||||
key = attrs[count+1];
|
||||
}
|
||||
if (attrs[count][0] == 'v' && attrs[count][1] == 0) {
|
||||
value = attrs[count+1];
|
||||
}
|
||||
}
|
||||
if (!m_tl_builder) {
|
||||
m_tl_builder = std::unique_ptr<osmium::builder::TagListBuilder>(new osmium::builder::TagListBuilder(m_buffer, builder));
|
||||
}
|
||||
m_tl_builder->add_tag(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void header_is_done() {
|
||||
if (!m_promise_fulfilled) {
|
||||
m_header_promise.set_value(m_header);
|
||||
m_promise_fulfilled = true;
|
||||
if (m_read_types == osmium::osm_entity_bits::nothing) {
|
||||
throw ParserIsDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void start_element(const XML_Char* element, const XML_Char** attrs) {
|
||||
switch (m_context) {
|
||||
case context::root:
|
||||
if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
|
||||
if (!strcmp(element, "osmChange")) {
|
||||
m_header.has_multiple_object_versions(true);
|
||||
}
|
||||
for (int count = 0; attrs[count]; count += 2) {
|
||||
if (!strcmp(attrs[count], "version")) {
|
||||
m_header.set("version", attrs[count+1]);
|
||||
if (strcmp(attrs[count+1], "0.6")) {
|
||||
throw osmium::format_version_error(attrs[count+1]);
|
||||
}
|
||||
} else if (!strcmp(attrs[count], "generator")) {
|
||||
m_header.set("generator", attrs[count+1]);
|
||||
}
|
||||
}
|
||||
if (m_header.get("version") == "") {
|
||||
throw osmium::format_version_error();
|
||||
}
|
||||
}
|
||||
m_context = context::top;
|
||||
break;
|
||||
case context::top:
|
||||
assert(!m_tl_builder);
|
||||
if (!strcmp(element, "node")) {
|
||||
header_is_done();
|
||||
if (m_read_types & osmium::osm_entity_bits::node) {
|
||||
m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
|
||||
m_node_builder->add_user(init_object(m_node_builder->object(), attrs));
|
||||
m_context = context::node;
|
||||
} else {
|
||||
m_context = context::ignored_node;
|
||||
}
|
||||
} else if (!strcmp(element, "way")) {
|
||||
header_is_done();
|
||||
if (m_read_types & osmium::osm_entity_bits::way) {
|
||||
m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
|
||||
m_way_builder->add_user(init_object(m_way_builder->object(), attrs));
|
||||
m_context = context::way;
|
||||
} else {
|
||||
m_context = context::ignored_way;
|
||||
}
|
||||
} else if (!strcmp(element, "relation")) {
|
||||
header_is_done();
|
||||
if (m_read_types & osmium::osm_entity_bits::relation) {
|
||||
m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
|
||||
m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs));
|
||||
m_context = context::relation;
|
||||
} else {
|
||||
m_context = context::ignored_relation;
|
||||
}
|
||||
} else if (!strcmp(element, "changeset")) {
|
||||
header_is_done();
|
||||
if (m_read_types & osmium::osm_entity_bits::changeset) {
|
||||
m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
|
||||
init_changeset(m_changeset_builder.get(), attrs);
|
||||
m_context = context::changeset;
|
||||
} else {
|
||||
m_context = context::ignored_changeset;
|
||||
}
|
||||
} else if (!strcmp(element, "bounds")) {
|
||||
osmium::Location min;
|
||||
osmium::Location max;
|
||||
for (int count = 0; attrs[count]; count += 2) {
|
||||
if (!strcmp(attrs[count], "minlon")) {
|
||||
min.lon(atof(attrs[count+1]));
|
||||
} else if (!strcmp(attrs[count], "minlat")) {
|
||||
min.lat(atof(attrs[count+1]));
|
||||
} else if (!strcmp(attrs[count], "maxlon")) {
|
||||
max.lon(atof(attrs[count+1]));
|
||||
} else if (!strcmp(attrs[count], "maxlat")) {
|
||||
max.lat(atof(attrs[count+1]));
|
||||
}
|
||||
}
|
||||
osmium::Box box;
|
||||
box.extend(min).extend(max);
|
||||
m_header.add_box(box);
|
||||
} else if (!strcmp(element, "delete")) {
|
||||
m_in_delete_section = true;
|
||||
}
|
||||
break;
|
||||
case context::node:
|
||||
m_last_context = context::node;
|
||||
m_context = context::in_object;
|
||||
check_tag(m_node_builder.get(), element, attrs);
|
||||
break;
|
||||
case context::way:
|
||||
m_last_context = context::way;
|
||||
m_context = context::in_object;
|
||||
if (!strcmp(element, "nd")) {
|
||||
m_tl_builder.reset();
|
||||
|
||||
if (!m_wnl_builder) {
|
||||
m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
|
||||
}
|
||||
|
||||
for (int count = 0; attrs[count]; count += 2) {
|
||||
if (!strcmp(attrs[count], "ref")) {
|
||||
m_wnl_builder->add_node_ref(osmium::string_to_object_id(attrs[count+1]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
check_tag(m_way_builder.get(), element, attrs);
|
||||
}
|
||||
break;
|
||||
case context::relation:
|
||||
m_last_context = context::relation;
|
||||
m_context = context::in_object;
|
||||
if (!strcmp(element, "member")) {
|
||||
m_tl_builder.reset();
|
||||
|
||||
if (!m_rml_builder) {
|
||||
m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get()));
|
||||
}
|
||||
|
||||
char type = 'x';
|
||||
object_id_type ref = 0;
|
||||
const char* role = "";
|
||||
for (int count = 0; attrs[count]; count += 2) {
|
||||
if (!strcmp(attrs[count], "type")) {
|
||||
type = static_cast<char>(attrs[count+1][0]);
|
||||
} else if (!strcmp(attrs[count], "ref")) {
|
||||
ref = osmium::string_to_object_id(attrs[count+1]);
|
||||
} else if (!strcmp(attrs[count], "role")) {
|
||||
role = static_cast<const char*>(attrs[count+1]);
|
||||
}
|
||||
}
|
||||
// XXX assert type, ref, role are set
|
||||
m_rml_builder->add_member(char_to_item_type(type), ref, role);
|
||||
} else {
|
||||
check_tag(m_relation_builder.get(), element, attrs);
|
||||
}
|
||||
break;
|
||||
case context::changeset:
|
||||
m_last_context = context::changeset;
|
||||
m_context = context::in_object;
|
||||
check_tag(m_changeset_builder.get(), element, attrs);
|
||||
break;
|
||||
case context::ignored_node:
|
||||
break;
|
||||
case context::ignored_way:
|
||||
break;
|
||||
case context::ignored_relation:
|
||||
break;
|
||||
case context::ignored_changeset:
|
||||
break;
|
||||
case context::in_object:
|
||||
assert(false); // should never be here
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void end_element(const XML_Char* element) {
|
||||
switch (m_context) {
|
||||
case context::root:
|
||||
assert(false); // should never be here
|
||||
break;
|
||||
case context::top:
|
||||
if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
|
||||
header_is_done();
|
||||
m_context = context::root;
|
||||
} else if (!strcmp(element, "delete")) {
|
||||
m_in_delete_section = false;
|
||||
}
|
||||
break;
|
||||
case context::node:
|
||||
assert(!strcmp(element, "node"));
|
||||
m_tl_builder.reset();
|
||||
m_node_builder.reset();
|
||||
m_buffer.commit();
|
||||
m_context = context::top;
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::way:
|
||||
assert(!strcmp(element, "way"));
|
||||
m_tl_builder.reset();
|
||||
m_wnl_builder.reset();
|
||||
m_way_builder.reset();
|
||||
m_buffer.commit();
|
||||
m_context = context::top;
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::relation:
|
||||
assert(!strcmp(element, "relation"));
|
||||
m_tl_builder.reset();
|
||||
m_rml_builder.reset();
|
||||
m_relation_builder.reset();
|
||||
m_buffer.commit();
|
||||
m_context = context::top;
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::changeset:
|
||||
assert(!strcmp(element, "changeset"));
|
||||
m_tl_builder.reset();
|
||||
m_changeset_builder.reset();
|
||||
m_buffer.commit();
|
||||
m_context = context::top;
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::in_object:
|
||||
m_context = m_last_context;
|
||||
break;
|
||||
case context::ignored_node:
|
||||
if (!strcmp(element, "node")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
case context::ignored_way:
|
||||
if (!strcmp(element, "way")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
case context::ignored_relation:
|
||||
if (!strcmp(element, "relation")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
case context::ignored_changeset:
|
||||
if (!strcmp(element, "changeset")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flush_buffer() {
|
||||
if (m_buffer.capacity() - m_buffer.committed() < 1000 * 1000) {
|
||||
m_queue.push(std::move(m_buffer));
|
||||
osmium::memory::Buffer buffer(buffer_size);
|
||||
std::swap(m_buffer, buffer);
|
||||
|
||||
while (m_queue.size() > m_max_queue_size) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // XMLParser
|
||||
|
||||
class XMLInputFormat : public osmium::io::detail::InputFormat {
|
||||
|
||||
static constexpr size_t m_max_queue_size = 100;
|
||||
|
||||
osmium::thread::Queue<osmium::memory::Buffer> m_queue;
|
||||
std::atomic<bool> m_done;
|
||||
std::promise<osmium::io::Header> m_header_promise;
|
||||
osmium::thread::CheckedTask<XMLParser> m_parser_task;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Instantiate XML Parser
|
||||
*
|
||||
* @param file osmium::io::File instance describing file to be read from.
|
||||
* @param read_which_entities Which types of OSM entities (nodes, ways, relations, changesets) should be parsed?
|
||||
* @param input_queue String queue where data is read from.
|
||||
*/
|
||||
explicit XMLInputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
|
||||
osmium::io::detail::InputFormat(file, read_which_entities, input_queue),
|
||||
m_queue(),
|
||||
m_done(false),
|
||||
m_header_promise(),
|
||||
m_parser_task(input_queue, m_queue, m_header_promise, read_which_entities, m_done) {
|
||||
}
|
||||
|
||||
~XMLInputFormat() {
|
||||
m_done = true;
|
||||
}
|
||||
|
||||
virtual osmium::io::Header header() override final {
|
||||
m_parser_task.check_for_exception();
|
||||
return m_header_promise.get_future().get();
|
||||
}
|
||||
|
||||
osmium::memory::Buffer read() override {
|
||||
osmium::memory::Buffer buffer;
|
||||
if (!m_done || !m_queue.empty()) {
|
||||
m_queue.wait_and_pop(buffer);
|
||||
}
|
||||
|
||||
m_parser_task.check_for_exception();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}; // class XMLInputFormat
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_xml_input = osmium::io::detail::InputFormatFactory::instance().register_input_format(osmium::io::file_format::xml,
|
||||
[](const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
|
||||
return new osmium::io::detail::XMLInputFormat(file, read_which_entities, input_queue);
|
||||
});
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
|
||||
-475
@@ -1,475 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <chrono>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ratio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct XMLWriteError {};
|
||||
|
||||
namespace {
|
||||
|
||||
void xml_string(std::string& out, const char* in) {
|
||||
for (; *in != '\0'; ++in) {
|
||||
switch(*in) {
|
||||
case '&': out += "&"; break;
|
||||
case '\"': out += """; break;
|
||||
case '\'': out += "'"; break;
|
||||
case '<': out += "<"; break;
|
||||
case '>': out += ">"; break;
|
||||
default: out += *in; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const size_t tmp_buffer_size = 100;
|
||||
|
||||
template <typename T>
|
||||
void oprintf(std::string& out, const char* format, T value) {
|
||||
char buffer[tmp_buffer_size+1];
|
||||
snprintf(buffer, sizeof(buffer)/sizeof(char), format, value);
|
||||
out += buffer;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class XMLOutputBlock : public osmium::handler::Handler {
|
||||
|
||||
// operation (create, modify, delete) for osc files
|
||||
enum class operation {
|
||||
op_none = 0,
|
||||
op_create = 1,
|
||||
op_modify = 2,
|
||||
op_delete = 3
|
||||
};
|
||||
|
||||
osmium::memory::Buffer m_input_buffer;
|
||||
|
||||
std::string m_out {};
|
||||
|
||||
operation m_last_op {operation::op_none};
|
||||
|
||||
const bool m_write_visible_flag;
|
||||
const bool m_write_change_ops;
|
||||
|
||||
void write_spaces(int num) {
|
||||
for (; num!=0; --num) {
|
||||
m_out += ' ';
|
||||
}
|
||||
}
|
||||
|
||||
void write_prefix() {
|
||||
if (m_write_change_ops) {
|
||||
write_spaces(4);
|
||||
} else {
|
||||
write_spaces(2);
|
||||
}
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
oprintf(m_out, " id=\"%" PRId64 "\"", object.id());
|
||||
|
||||
if (object.version()) {
|
||||
oprintf(m_out, " version=\"%d\"", object.version());
|
||||
}
|
||||
|
||||
if (object.timestamp()) {
|
||||
m_out += " timestamp=\"";
|
||||
m_out += object.timestamp().to_iso();
|
||||
m_out += "\"";
|
||||
}
|
||||
|
||||
if (!object.user_is_anonymous()) {
|
||||
oprintf(m_out, " uid=\"%d\" user=\"", object.uid());
|
||||
xml_string(m_out, object.user());
|
||||
m_out += "\"";
|
||||
}
|
||||
|
||||
if (object.changeset()) {
|
||||
oprintf(m_out, " changeset=\"%d\"", object.changeset());
|
||||
}
|
||||
|
||||
if (m_write_visible_flag) {
|
||||
if (object.visible()) {
|
||||
m_out += " visible=\"true\"";
|
||||
} else {
|
||||
m_out += " visible=\"false\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write_tags(const osmium::TagList& tags) {
|
||||
for (const auto& tag : tags) {
|
||||
write_prefix();
|
||||
m_out += " <tag k=\"";
|
||||
xml_string(m_out, tag.key());
|
||||
m_out += "\" v=\"";
|
||||
xml_string(m_out, tag.value());
|
||||
m_out += "\"/>\n";
|
||||
}
|
||||
}
|
||||
|
||||
void open_close_op_tag(const operation op = operation::op_none) {
|
||||
if (op == m_last_op) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_last_op) {
|
||||
case operation::op_none:
|
||||
break;
|
||||
case operation::op_create:
|
||||
m_out += " </create>\n";
|
||||
break;
|
||||
case operation::op_modify:
|
||||
m_out += " </modify>\n";
|
||||
break;
|
||||
case operation::op_delete:
|
||||
m_out += " </delete>\n";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case operation::op_none:
|
||||
break;
|
||||
case operation::op_create:
|
||||
m_out += " <create>\n";
|
||||
break;
|
||||
case operation::op_modify:
|
||||
m_out += " <modify>\n";
|
||||
break;
|
||||
case operation::op_delete:
|
||||
m_out += " <delete>\n";
|
||||
break;
|
||||
}
|
||||
|
||||
m_last_op = op;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit XMLOutputBlock(osmium::memory::Buffer&& buffer, bool write_visible_flag, bool write_change_ops) :
|
||||
m_input_buffer(std::move(buffer)),
|
||||
m_write_visible_flag(write_visible_flag && !write_change_ops),
|
||||
m_write_change_ops(write_change_ops) {
|
||||
}
|
||||
|
||||
XMLOutputBlock(const XMLOutputBlock&) = delete;
|
||||
XMLOutputBlock& operator=(const XMLOutputBlock&) = delete;
|
||||
|
||||
XMLOutputBlock(XMLOutputBlock&& other) = default;
|
||||
XMLOutputBlock& operator=(XMLOutputBlock&& other) = default;
|
||||
|
||||
std::string operator()() {
|
||||
osmium::apply(m_input_buffer.cbegin(), m_input_buffer.cend(), *this);
|
||||
|
||||
if (m_write_change_ops) {
|
||||
open_close_op_tag();
|
||||
}
|
||||
|
||||
std::string out;
|
||||
std::swap(out, m_out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
if (m_write_change_ops) {
|
||||
open_close_op_tag(node.visible() ? (node.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
|
||||
}
|
||||
|
||||
write_prefix();
|
||||
m_out += "<node";
|
||||
|
||||
write_meta(node);
|
||||
|
||||
if (node.location()) {
|
||||
m_out += " lat=\"";
|
||||
osmium::Location::coordinate2string(std::back_inserter(m_out), node.location().lat_without_check());
|
||||
m_out += "\" lon=\"";
|
||||
osmium::Location::coordinate2string(std::back_inserter(m_out), node.location().lon_without_check());
|
||||
m_out += "\"";
|
||||
}
|
||||
|
||||
if (node.tags().empty()) {
|
||||
m_out += "/>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
m_out += ">\n";
|
||||
|
||||
write_tags(node.tags());
|
||||
|
||||
write_prefix();
|
||||
m_out += "</node>\n";
|
||||
}
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
if (m_write_change_ops) {
|
||||
open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
|
||||
}
|
||||
|
||||
write_prefix();
|
||||
m_out += "<way";
|
||||
write_meta(way);
|
||||
|
||||
if (way.tags().empty() && way.nodes().empty()) {
|
||||
m_out += "/>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
m_out += ">\n";
|
||||
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
write_prefix();
|
||||
oprintf(m_out, " <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
|
||||
}
|
||||
|
||||
write_tags(way.tags());
|
||||
|
||||
write_prefix();
|
||||
m_out += "</way>\n";
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
if (m_write_change_ops) {
|
||||
open_close_op_tag(relation.visible() ? (relation.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
|
||||
}
|
||||
|
||||
write_prefix();
|
||||
m_out += "<relation";
|
||||
write_meta(relation);
|
||||
|
||||
if (relation.tags().empty() && relation.members().empty()) {
|
||||
m_out += "/>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
m_out += ">\n";
|
||||
|
||||
for (const auto& member : relation.members()) {
|
||||
write_prefix();
|
||||
m_out += " <member type=\"";
|
||||
m_out += item_type_to_name(member.type());
|
||||
oprintf(m_out, "\" ref=\"%" PRId64 "\" role=\"", member.ref());
|
||||
xml_string(m_out, member.role());
|
||||
m_out += "\"/>\n";
|
||||
}
|
||||
|
||||
write_tags(relation.tags());
|
||||
|
||||
write_prefix();
|
||||
m_out += "</relation>\n";
|
||||
}
|
||||
|
||||
void changeset(const osmium::Changeset& changeset) {
|
||||
write_prefix();
|
||||
m_out += "<changeset";
|
||||
|
||||
oprintf(m_out, " id=\"%" PRId32 "\"", changeset.id());
|
||||
|
||||
if (changeset.created_at()) {
|
||||
m_out += " created_at=\"";
|
||||
m_out += changeset.created_at().to_iso();
|
||||
m_out += "\"";
|
||||
}
|
||||
|
||||
oprintf(m_out, " num_changes=\"%" PRId32 "\"", changeset.num_changes());
|
||||
|
||||
if (changeset.closed_at()) {
|
||||
m_out += " closed_at=\"";
|
||||
m_out += changeset.closed_at().to_iso();
|
||||
m_out += "\" open=\"false\"";
|
||||
} else {
|
||||
m_out += " open=\"true\"";
|
||||
}
|
||||
|
||||
if (changeset.bounds()) {
|
||||
oprintf(m_out, " min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check());
|
||||
oprintf(m_out, " min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check());
|
||||
oprintf(m_out, " max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check());
|
||||
oprintf(m_out, " max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check());
|
||||
}
|
||||
|
||||
if (!changeset.user_is_anonymous()) {
|
||||
m_out += " user=\"";
|
||||
xml_string(m_out, changeset.user());
|
||||
oprintf(m_out, "\" uid=\"%d\"", changeset.uid());
|
||||
}
|
||||
|
||||
if (changeset.tags().empty()) {
|
||||
m_out += "/>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
m_out += ">\n";
|
||||
|
||||
write_tags(changeset.tags());
|
||||
|
||||
write_prefix();
|
||||
m_out += "</changeset>\n";
|
||||
}
|
||||
|
||||
}; // class XMLOutputBlock
|
||||
|
||||
class XMLOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
|
||||
|
||||
bool m_write_visible_flag;
|
||||
|
||||
public:
|
||||
|
||||
XMLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
|
||||
OutputFormat(file, output_queue),
|
||||
m_write_visible_flag(file.has_multiple_object_versions() || m_file.is_true("force_visible_flag")) {
|
||||
}
|
||||
|
||||
XMLOutputFormat(const XMLOutputFormat&) = delete;
|
||||
XMLOutputFormat& operator=(const XMLOutputFormat&) = delete;
|
||||
|
||||
~XMLOutputFormat() override final {
|
||||
}
|
||||
|
||||
void write_buffer(osmium::memory::Buffer&& buffer) override final {
|
||||
XMLOutputBlock output_block(std::move(buffer), m_write_visible_flag, m_file.is_true("xml_change_format"));
|
||||
m_output_queue.push(osmium::thread::Pool::instance().submit(std::move(output_block)));
|
||||
while (m_output_queue.size() > 10) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // XXX
|
||||
}
|
||||
}
|
||||
|
||||
void write_header(const osmium::io::Header& header) override final {
|
||||
std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
|
||||
if (m_file.is_true("xml_change_format")) {
|
||||
out += "<osmChange version=\"0.6\" generator=\"";
|
||||
xml_string(out, header.get("generator").c_str());
|
||||
out += "\">\n";
|
||||
} else {
|
||||
out += "<osm version=\"0.6\"";
|
||||
|
||||
std::string xml_josm_upload = header.get("xml_josm_upload");
|
||||
if (xml_josm_upload == "true" || xml_josm_upload == "false") {
|
||||
out += " upload=\"";
|
||||
out += xml_josm_upload;
|
||||
out += "\"";
|
||||
}
|
||||
out += " generator=\"";
|
||||
xml_string(out, header.get("generator").c_str());
|
||||
out += "\">\n";
|
||||
}
|
||||
|
||||
for (const auto& box : header.boxes()) {
|
||||
out += " <bounds";
|
||||
oprintf(out, " minlon=\"%.7f\"", box.bottom_left().lon());
|
||||
oprintf(out, " minlat=\"%.7f\"", box.bottom_left().lat());
|
||||
oprintf(out, " maxlon=\"%.7f\"", box.top_right().lon());
|
||||
oprintf(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat());
|
||||
}
|
||||
|
||||
std::promise<std::string> promise;
|
||||
m_output_queue.push(promise.get_future());
|
||||
promise.set_value(std::move(out));
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
{
|
||||
std::string out;
|
||||
if (m_file.is_true("xml_change_format")) {
|
||||
out += "</osmChange>\n";
|
||||
} else {
|
||||
out += "</osm>\n";
|
||||
}
|
||||
|
||||
std::promise<std::string> promise;
|
||||
m_output_queue.push(promise.get_future());
|
||||
promise.set_value(std::move(out));
|
||||
}
|
||||
|
||||
std::promise<std::string> promise;
|
||||
m_output_queue.push(promise.get_future());
|
||||
promise.set_value(std::string());
|
||||
}
|
||||
|
||||
}; // class XMLOutputFormat
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml,
|
||||
[](const osmium::io::File& file, data_queue_type& output_queue) {
|
||||
return new osmium::io::detail::XMLOutputFormat(file, output_queue);
|
||||
});
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace output
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
|
||||
Vendored
-98
@@ -1,98 +0,0 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_ZLIB_HPP
|
||||
#define OSMIUM_IO_DETAIL_ZLIB_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Compress data using zlib.
|
||||
*
|
||||
* @param input Data to compress.
|
||||
* @return Compressed data.
|
||||
*/
|
||||
inline std::string zlib_compress(const std::string& input) {
|
||||
unsigned long output_size = ::compressBound(input.size());
|
||||
|
||||
std::string output(output_size, '\0');
|
||||
|
||||
if (::compress(reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
|
||||
&output_size,
|
||||
reinterpret_cast<const unsigned char*>(input.data()),
|
||||
input.size()) != Z_OK) {
|
||||
throw std::runtime_error("failed to compress data");
|
||||
}
|
||||
|
||||
output.resize(output_size);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompress data using zlib.
|
||||
*
|
||||
* @param input Compressed input data.
|
||||
* @param raw_size Size of uncompressed data.
|
||||
* @return Uncompressed data.
|
||||
*/
|
||||
inline std::string zlib_uncompress(const std::string& input, unsigned long raw_size) {
|
||||
std::string output(raw_size, '\0');
|
||||
|
||||
if (::uncompress(reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
|
||||
&raw_size,
|
||||
reinterpret_cast<const unsigned char*>(input.data()),
|
||||
input.size()) != Z_OK) {
|
||||
throw std::runtime_error("failed to uncompress data");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_ZLIB_HPP
|
||||
Vendored
-319
@@ -1,319 +0,0 @@
|
||||
#ifndef OSMIUM_IO_FILE_HPP
|
||||
#define OSMIUM_IO_FILE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
#include <osmium/util/options.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
struct io_error : public std::runtime_error {
|
||||
|
||||
io_error(const std::string& what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
io_error(const char* what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
}; // struct io_error
|
||||
|
||||
/**
|
||||
* @brief Everything related to input and output of OSM data.
|
||||
*/
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline std::vector<std::string> split(const std::string& in, const char delim) {
|
||||
std::vector<std::string> result;
|
||||
std::stringstream ss(in);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim)) {
|
||||
result.push_back(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* This class describes an OSM file in one of several different formats.
|
||||
*
|
||||
* If the filename is empty or "-", this means stdin or stdout is used.
|
||||
*/
|
||||
class File : public osmium::util::Options {
|
||||
|
||||
private:
|
||||
|
||||
std::string m_filename;
|
||||
|
||||
std::string m_format_string;
|
||||
|
||||
file_format m_file_format {file_format::unknown};
|
||||
|
||||
file_compression m_file_compression {file_compression::none};
|
||||
|
||||
bool m_has_multiple_object_versions {false};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create File using type and encoding from filename or given
|
||||
* format specification.
|
||||
*
|
||||
* @param filename Filename including suffix. The type and encoding
|
||||
* of the file will be taken from the suffix.
|
||||
* An empty filename or "-" means stdin or stdout.
|
||||
* @param format File format as string. See the description of the
|
||||
* parse_format() function for details.
|
||||
*/
|
||||
explicit File(const std::string& filename = "", const std::string& format = "") :
|
||||
Options(),
|
||||
m_filename(filename),
|
||||
m_format_string(format) {
|
||||
|
||||
// stdin/stdout
|
||||
if (filename == "" || filename == "-") {
|
||||
m_filename = "";
|
||||
default_settings_for_stdinout();
|
||||
}
|
||||
|
||||
// filename is actually a URL
|
||||
std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
|
||||
if (protocol == "http" || protocol == "https") {
|
||||
default_settings_for_url();
|
||||
}
|
||||
|
||||
detect_format_from_suffix(m_filename);
|
||||
|
||||
if (format != "") {
|
||||
parse_format(format);
|
||||
}
|
||||
}
|
||||
|
||||
File(const File& other) = default;
|
||||
File& operator=(const File& other) = default;
|
||||
|
||||
File(File&& other) = default;
|
||||
File& operator=(File&& other) = default;
|
||||
|
||||
~File() = default;
|
||||
|
||||
void parse_format(const std::string& format) {
|
||||
std::vector<std::string> options = detail::split(format, ',');
|
||||
|
||||
// if the first item in the format list doesn't contain
|
||||
// an equals sign, it is a format
|
||||
if (!options.empty() && options[0].find_first_of('=') == std::string::npos) {
|
||||
detect_format_from_suffix(options[0]);
|
||||
options.erase(options.begin());
|
||||
}
|
||||
|
||||
for (auto& option : options) {
|
||||
size_t pos = option.find_first_of('=');
|
||||
if (pos == std::string::npos) {
|
||||
set(option, true);
|
||||
} else {
|
||||
std::string value = option.substr(pos+1);
|
||||
option.erase(pos);
|
||||
set(option, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (get("history") == "true") {
|
||||
m_has_multiple_object_versions = true;
|
||||
} else if (get("history") == "false") {
|
||||
m_has_multiple_object_versions = false;
|
||||
}
|
||||
}
|
||||
|
||||
void detect_format_from_suffix(const std::string& name) {
|
||||
std::vector<std::string> suffixes = detail::split(name, '.');
|
||||
|
||||
if (suffixes.empty()) return;
|
||||
|
||||
// if the last suffix is one of a known set of compressions,
|
||||
// set that compression
|
||||
if (suffixes.back() == "gz") {
|
||||
m_file_compression = file_compression::gzip;
|
||||
suffixes.pop_back();
|
||||
} else if (suffixes.back() == "bz2") {
|
||||
m_file_compression = file_compression::bzip2;
|
||||
suffixes.pop_back();
|
||||
}
|
||||
|
||||
if (suffixes.empty()) return;
|
||||
|
||||
// if the last suffix is one of a known set of formats,
|
||||
// set that format
|
||||
if (suffixes.back() == "pbf") {
|
||||
m_file_format = file_format::pbf;
|
||||
suffixes.pop_back();
|
||||
} else if (suffixes.back() == "xml") {
|
||||
m_file_format = file_format::xml;
|
||||
suffixes.pop_back();
|
||||
} else if (suffixes.back() == "opl") {
|
||||
m_file_format = file_format::opl;
|
||||
suffixes.pop_back();
|
||||
}
|
||||
|
||||
if (suffixes.empty()) return;
|
||||
|
||||
if (suffixes.back() == "osm") {
|
||||
if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
|
||||
suffixes.pop_back();
|
||||
} else if (suffixes.back() == "osh") {
|
||||
if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
|
||||
m_has_multiple_object_versions = true;
|
||||
suffixes.pop_back();
|
||||
} else if (suffixes.back() == "osc") {
|
||||
if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
|
||||
m_has_multiple_object_versions = true;
|
||||
set("xml_change_format", true);
|
||||
suffixes.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check file format etc. for consistency and throw exception if there
|
||||
* is a problem.
|
||||
*
|
||||
* @throws std::runtime_error
|
||||
*/
|
||||
void check() const {
|
||||
if (m_file_format == file_format::unknown) {
|
||||
std::string msg = "Could not detect file format";
|
||||
if (!m_format_string.empty()) {
|
||||
msg += " from format string '";
|
||||
msg += m_format_string;
|
||||
msg += "'";
|
||||
}
|
||||
if (m_filename.empty()) {
|
||||
msg += " for stdin/stdout";
|
||||
} else {
|
||||
msg += " for filename '";
|
||||
msg += m_filename;
|
||||
msg += "'";
|
||||
}
|
||||
msg += ".";
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default settings for type and encoding when the filename is
|
||||
* empty or "-". If you want to have a different default setting
|
||||
* override this in a subclass.
|
||||
*/
|
||||
void default_settings_for_stdinout() {
|
||||
m_file_format = file_format::unknown;
|
||||
m_file_compression = file_compression::none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default settings for type and encoding when the filename is
|
||||
* a normal file. If you want to have a different default setting
|
||||
* override this in a subclass.
|
||||
*/
|
||||
void default_settings_for_file() {
|
||||
m_file_format = file_format::unknown;
|
||||
m_file_compression = file_compression::none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default settings for type and encoding when the filename is a URL.
|
||||
* If you want to have a different default setting override this in a
|
||||
* subclass.
|
||||
*/
|
||||
void default_settings_for_url() {
|
||||
m_file_format = file_format::xml;
|
||||
m_file_compression = file_compression::none;
|
||||
}
|
||||
|
||||
file_format format() const {
|
||||
return m_file_format;
|
||||
}
|
||||
|
||||
File& format(file_format format) {
|
||||
m_file_format = format;
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_compression compression() const {
|
||||
return m_file_compression;
|
||||
}
|
||||
|
||||
File& compression(file_compression compression) {
|
||||
m_file_compression = compression;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool has_multiple_object_versions() const {
|
||||
return m_has_multiple_object_versions;
|
||||
}
|
||||
|
||||
File& has_multiple_object_versions(bool value) {
|
||||
m_has_multiple_object_versions = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
File& filename(const std::string& filename) {
|
||||
if (filename == "-") {
|
||||
m_filename = "";
|
||||
} else {
|
||||
m_filename = filename;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string& filename() const {
|
||||
return m_filename;
|
||||
}
|
||||
|
||||
}; // class File
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_FILE_HPP
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
#ifndef OSMIUM_IO_FILE_COMPRESSION_HPP
|
||||
#define OSMIUM_IO_FILE_COMPRESSION_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
enum class file_compression {
|
||||
none = 0,
|
||||
gzip = 1,
|
||||
bzip2 = 2
|
||||
};
|
||||
|
||||
inline const char* as_string(file_compression compression) {
|
||||
switch (compression) {
|
||||
case file_compression::none:
|
||||
return "none";
|
||||
case file_compression::gzip:
|
||||
return "gzip";
|
||||
case file_compression::bzip2:
|
||||
return "bzip2";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_compression compression) {
|
||||
return out << as_string(compression);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_FILE_COMPRESSION_HPP
|
||||
Vendored
-74
@@ -1,74 +0,0 @@
|
||||
#ifndef OSMIUM_IO_FILE_FORMAT_HPP
|
||||
#define OSMIUM_IO_FILE_FORMAT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
enum class file_format {
|
||||
unknown = 0,
|
||||
xml = 1,
|
||||
pbf = 2,
|
||||
opl = 3,
|
||||
json = 4
|
||||
};
|
||||
|
||||
inline const char* as_string(file_format format) {
|
||||
switch (format) {
|
||||
case file_format::unknown:
|
||||
return "unknown";
|
||||
case file_format::xml:
|
||||
return "XML";
|
||||
case file_format::pbf:
|
||||
return "PBF";
|
||||
case file_format::opl:
|
||||
return "OPL";
|
||||
case file_format::json:
|
||||
return "JSON";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_format format) {
|
||||
return out << as_string(format);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_FILE_FORMAT_HPP
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
#ifndef OSMIUM_IO_GZIP_COMPRESSION_HPP
|
||||
#define OSMIUM_IO_GZIP_COMPRESSION_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class GzipCompressor : public Compressor {
|
||||
|
||||
gzFile m_gzfile;
|
||||
|
||||
public:
|
||||
|
||||
explicit GzipCompressor(int fd) :
|
||||
Compressor(),
|
||||
m_gzfile(::gzdopen(fd, "w")) {
|
||||
if (!m_gzfile) {
|
||||
throw std::runtime_error("initialization of gzip compression failed");
|
||||
}
|
||||
}
|
||||
|
||||
~GzipCompressor() override final {
|
||||
this->close();
|
||||
}
|
||||
|
||||
void write(const std::string& data) override final {
|
||||
::gzwrite(m_gzfile, data.data(), data.size());
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
if (m_gzfile) {
|
||||
::gzclose(m_gzfile);
|
||||
m_gzfile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}; // class GzipCompressor
|
||||
|
||||
class GzipDecompressor : public Decompressor {
|
||||
|
||||
gzFile m_gzfile;
|
||||
|
||||
public:
|
||||
|
||||
explicit GzipDecompressor(int fd) :
|
||||
Decompressor(),
|
||||
m_gzfile(::gzdopen(fd, "r")) {
|
||||
if (!m_gzfile) {
|
||||
throw std::runtime_error("initialization of gzip compression failed");
|
||||
}
|
||||
}
|
||||
|
||||
~GzipDecompressor() override final {
|
||||
this->close();
|
||||
}
|
||||
|
||||
std::string read() override final {
|
||||
std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
|
||||
int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), buffer.size());
|
||||
if (nread < 0) {
|
||||
throw std::runtime_error("gzip read failed"); // XXX better error detection and reporting
|
||||
// throw std::system_error(errno, std::system_category(), "Read failed");
|
||||
}
|
||||
buffer.resize(static_cast<std::string::size_type>(nread));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void close() override final {
|
||||
if (m_gzfile) {
|
||||
::gzclose(m_gzfile);
|
||||
m_gzfile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}; // class GzipDecompressor
|
||||
|
||||
namespace {
|
||||
|
||||
const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
|
||||
[](int fd) { return new osmium::io::GzipCompressor(fd); },
|
||||
[](int fd) { return new osmium::io::GzipDecompressor(fd); }
|
||||
);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_GZIP_COMPRESSION_HPP
|
||||
Vendored
-122
@@ -1,122 +0,0 @@
|
||||
#ifndef OSMIUM_IO_HEADER_HPP
|
||||
#define OSMIUM_IO_HEADER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/util/options.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
/**
|
||||
* Meta information from the header of an OSM file.
|
||||
*/
|
||||
class Header : public osmium::util::Options {
|
||||
|
||||
/// Bounding boxes
|
||||
std::vector<osmium::Box> m_boxes;
|
||||
|
||||
/**
|
||||
* Are there possibly multiple versions of the same object in this stream of objects?
|
||||
* This is true for history files and for change files, but not for normal OSM files.
|
||||
*/
|
||||
bool m_has_multiple_object_versions = false;
|
||||
|
||||
public:
|
||||
|
||||
Header() = default;
|
||||
|
||||
explicit Header(std::initializer_list<osmium::util::Options::value_type> values) :
|
||||
Options(values) {
|
||||
}
|
||||
|
||||
Header(const Header&) = default;
|
||||
Header& operator=(const Header&) = default;
|
||||
|
||||
Header(Header&&) = default;
|
||||
Header& operator=(Header&&) = default;
|
||||
|
||||
~Header() = default;
|
||||
|
||||
std::vector<osmium::Box>& boxes() {
|
||||
return m_boxes;
|
||||
}
|
||||
|
||||
const std::vector<osmium::Box>& boxes() const {
|
||||
return m_boxes;
|
||||
}
|
||||
|
||||
Header& boxes(const std::vector<osmium::Box>& boxes) {
|
||||
m_boxes = boxes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
osmium::Box box() const {
|
||||
return m_boxes.empty() ? osmium::Box() : m_boxes.front();
|
||||
}
|
||||
|
||||
osmium::Box joined_boxes() const {
|
||||
osmium::Box box;
|
||||
for (const auto& b : m_boxes) {
|
||||
box.extend(b.bottom_left());
|
||||
box.extend(b.top_right());
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
Header& add_box(const osmium::Box& box) {
|
||||
m_boxes.push_back(box);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool has_multiple_object_versions() const {
|
||||
return m_has_multiple_object_versions;
|
||||
}
|
||||
|
||||
Header& has_multiple_object_versions(bool h) {
|
||||
m_has_multiple_object_versions = h;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}; // class Header
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_HEADER_HPP
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
#ifndef OSMIUM_IO_INPUT_ITERATOR_HPP
|
||||
#define OSMIUM_IO_INPUT_ITERATOR_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
/**
|
||||
* This iterator class allows you to iterate over all items from a
|
||||
* source. It hides all the buffer handling and makes the contents of a
|
||||
* source accessible as a normal STL input iterator.
|
||||
*/
|
||||
template <class TSource, class TItem = osmium::memory::Item>
|
||||
class InputIterator {
|
||||
|
||||
static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item");
|
||||
|
||||
typedef typename osmium::memory::Buffer::t_iterator<TItem> item_iterator;
|
||||
|
||||
TSource* m_source;
|
||||
std::shared_ptr<osmium::memory::Buffer> m_buffer {};
|
||||
item_iterator m_iter {};
|
||||
|
||||
void update_buffer() {
|
||||
do {
|
||||
m_buffer = std::make_shared<osmium::memory::Buffer>(std::move(m_source->read()));
|
||||
if (!m_buffer || !*m_buffer) { // end of input
|
||||
m_source = nullptr;
|
||||
m_buffer.reset();
|
||||
m_iter = item_iterator();
|
||||
return;
|
||||
}
|
||||
m_iter = m_buffer->begin<TItem>();
|
||||
} while (m_iter == m_buffer->end<TItem>());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
typedef TItem value_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef TItem* pointer;
|
||||
typedef TItem& reference;
|
||||
|
||||
explicit InputIterator(TSource& source) :
|
||||
m_source(&source) {
|
||||
update_buffer();
|
||||
}
|
||||
|
||||
// end iterator
|
||||
InputIterator() :
|
||||
m_source(nullptr) {
|
||||
}
|
||||
|
||||
InputIterator& operator++() {
|
||||
assert(m_source);
|
||||
assert(m_buffer);
|
||||
assert(m_iter);
|
||||
++m_iter;
|
||||
if (m_iter == m_buffer->end<TItem>()) {
|
||||
update_buffer();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
InputIterator operator++(int) {
|
||||
InputIterator tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const InputIterator& rhs) const {
|
||||
return m_source == rhs.m_source &&
|
||||
m_buffer == rhs.m_buffer &&
|
||||
m_iter == rhs.m_iter;
|
||||
}
|
||||
|
||||
bool operator!=(const InputIterator& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
assert(m_iter);
|
||||
return static_cast<reference>(*m_iter);
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
assert(m_iter);
|
||||
return &static_cast<reference>(*m_iter);
|
||||
}
|
||||
|
||||
}; // class InputIterator
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_INPUT_ITERATOR_HPP
|
||||
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
#ifndef OSMIUM_IO_OPL_OUTPUT_HPP
|
||||
#define OSMIUM_IO_OPL_OUTPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/writer.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/opl_output_format.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_OPL_OUTPUT_HPP
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
#ifndef OSMIUM_IO_OUTPUT_ITERATOR_HPP
|
||||
#define OSMIUM_IO_OUTPUT_ITERATOR_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/diff_object.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace memory {
|
||||
class Item;
|
||||
} // namespace memory
|
||||
|
||||
namespace io {
|
||||
|
||||
template <class TDest>
|
||||
class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> {
|
||||
|
||||
struct buffer_wrapper {
|
||||
osmium::memory::Buffer buffer;
|
||||
|
||||
buffer_wrapper(size_t buffer_size) :
|
||||
buffer(buffer_size, osmium::memory::Buffer::auto_grow::no) {
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr size_t default_buffer_size = 10 * 1024 * 1024;
|
||||
|
||||
TDest& m_destination;
|
||||
|
||||
std::shared_ptr<buffer_wrapper> m_buffer_wrapper;
|
||||
|
||||
public:
|
||||
|
||||
explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) :
|
||||
m_destination(destination),
|
||||
m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) {
|
||||
}
|
||||
|
||||
void flush() {
|
||||
osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no);
|
||||
std::swap(m_buffer_wrapper->buffer, buffer);
|
||||
m_destination(std::move(buffer));
|
||||
}
|
||||
|
||||
OutputIterator& operator=(const osmium::memory::Item& item) {
|
||||
try {
|
||||
m_buffer_wrapper->buffer.push_back(item);
|
||||
} catch (osmium::memory::BufferIsFull&) {
|
||||
flush();
|
||||
m_buffer_wrapper->buffer.push_back(item);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputIterator& operator=(const osmium::DiffObject& diff) {
|
||||
return this->operator=(diff.curr());
|
||||
}
|
||||
|
||||
OutputIterator& operator*() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputIterator& operator++() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputIterator& operator++(int) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
}; // class OutputIterator
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_OUTPUT_ITERATOR_HPP
|
||||
Vendored
-52
@@ -1,52 +0,0 @@
|
||||
#ifndef OSMIUM_IO_OVERWRITE_HPP
|
||||
#define OSMIUM_IO_OVERWRITE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
/**
|
||||
* Allow overwriting of existing file.
|
||||
*/
|
||||
enum class overwrite : bool {
|
||||
no = false,
|
||||
allow = true
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_OVERWRITE_HPP
|
||||
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
#ifndef OSMIUM_IO_PBF_INPUT_HPP
|
||||
#define OSMIUM_IO_PBF_INPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/reader.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/pbf_input_format.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_PBF_INPUT_HPP
|
||||
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
#ifndef OSMIUM_IO_PBF_OUTPUT_HPP
|
||||
#define OSMIUM_IO_PBF_OUTPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/writer.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/pbf_output_format.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_PBF_OUTPUT_HPP
|
||||
Vendored
-268
@@ -1,268 +0,0 @@
|
||||
#ifndef OSMIUM_IO_READER_HPP
|
||||
#define OSMIUM_IO_READER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sys/wait.h>
|
||||
#include <system_error>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/read_thread.hpp>
|
||||
#include <osmium/io/detail/read_write.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/thread/checked_task.hpp>
|
||||
#include <osmium/thread/name.hpp>
|
||||
#include <osmium/thread/queue.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
/**
|
||||
* This is the user-facing interface for reading OSM files. Instantiate
|
||||
* an object of this class with a file name or osmium::io::File object
|
||||
* and then call read() on it in a loop until it returns an invalid
|
||||
* Buffer.
|
||||
*/
|
||||
class Reader {
|
||||
|
||||
osmium::io::File m_file;
|
||||
osmium::osm_entity_bits::type m_read_which_entities;
|
||||
std::atomic<bool> m_input_done;
|
||||
int m_childpid;
|
||||
|
||||
osmium::thread::Queue<std::string> m_input_queue;
|
||||
|
||||
std::unique_ptr<osmium::io::Decompressor> m_decompressor;
|
||||
osmium::thread::CheckedTask<detail::ReadThread> m_read_task;
|
||||
|
||||
std::unique_ptr<osmium::io::detail::InputFormat> m_input;
|
||||
|
||||
/**
|
||||
* Fork and execute the given command in the child.
|
||||
* A pipe is created between the child and the parent.
|
||||
* The child writes to the pipe, the parent reads from it.
|
||||
* This function never returns in the child.
|
||||
*
|
||||
* @param command Command to execute in the child.
|
||||
* @param filename Filename to give to command as argument.
|
||||
* @return File descriptor of pipe in the parent.
|
||||
* @throws std::system_error if a system call fails.
|
||||
*/
|
||||
static int execute(const std::string& command, const std::string& filename, int* childpid) {
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "opening pipe failed");
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "fork failed");
|
||||
}
|
||||
if (pid == 0) { // child
|
||||
// close all file descriptors except one end of the pipe
|
||||
for (int i=0; i < 32; ++i) {
|
||||
if (i != pipefd[1]) {
|
||||
::close(i);
|
||||
}
|
||||
}
|
||||
if (dup2(pipefd[1], 1) < 0) { // put end of pipe as stdout/stdin
|
||||
exit(1);
|
||||
}
|
||||
|
||||
::open("/dev/null", O_RDONLY); // stdin
|
||||
::open("/dev/null", O_WRONLY); // stderr
|
||||
// hack: -g switches off globbing in curl which allows [] to be used in file names
|
||||
// this is important for XAPI URLs
|
||||
// in theory this execute() function could be used for other commands, but it is
|
||||
// only used for curl at the moment, so this is okay.
|
||||
if (::execlp(command.c_str(), command.c_str(), "-g", filename.c_str(), nullptr) < 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
// parent
|
||||
*childpid = pid;
|
||||
::close(pipefd[1]);
|
||||
return pipefd[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Open File for reading. Handles URLs or normal files. URLs
|
||||
* are opened by executing the "curl" program (which must be installed)
|
||||
* and reading from its output.
|
||||
*
|
||||
* @return File descriptor of open file or pipe.
|
||||
* @throws std::system_error if a system call fails.
|
||||
*/
|
||||
static int open_input_file_or_url(const std::string& filename, int* childpid) {
|
||||
std::string protocol = filename.substr(0, filename.find_first_of(':'));
|
||||
if (protocol == "http" || protocol == "https" || protocol == "ftp" || protocol == "file") {
|
||||
return execute("curl", filename, childpid);
|
||||
} else {
|
||||
return osmium::io::detail::open_for_reading(filename);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create new Reader object.
|
||||
*
|
||||
* @param file The file we want to open.
|
||||
* @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets)
|
||||
* should be read from the input file. It can speed the read up
|
||||
* significantly if objects that are not needed anyway are not
|
||||
* parsed.
|
||||
*/
|
||||
explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
|
||||
m_file(file),
|
||||
m_read_which_entities(read_which_entities),
|
||||
m_input_done(false),
|
||||
m_childpid(0),
|
||||
m_input_queue(),
|
||||
m_decompressor(osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
|
||||
m_read_task(m_input_queue, m_decompressor.get(), m_input_done),
|
||||
m_input(osmium::io::detail::InputFormatFactory::instance().create_input(m_file, m_read_which_entities, m_input_queue)) {
|
||||
}
|
||||
|
||||
explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
|
||||
Reader(osmium::io::File(filename), read_types) {
|
||||
}
|
||||
|
||||
explicit Reader(const char* filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
|
||||
Reader(osmium::io::File(filename), read_types) {
|
||||
}
|
||||
|
||||
Reader(const Reader&) = delete;
|
||||
Reader& operator=(const Reader&) = delete;
|
||||
|
||||
~Reader() {
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close down the Reader. A call to this is optional, because the
|
||||
* destructor of Reader will also call this. But if you don't call
|
||||
* this function first, the destructor might throw an exception
|
||||
* which is not good.
|
||||
*
|
||||
* @throws Some form of std::runtime_error when there is a problem.
|
||||
*/
|
||||
void close() {
|
||||
// Signal to input child process that it should wrap up.
|
||||
m_input_done = true;
|
||||
|
||||
m_input->close();
|
||||
|
||||
if (m_childpid) {
|
||||
int status;
|
||||
pid_t pid = ::waitpid(m_childpid, &status, 0);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
throw std::system_error(errno, std::system_category(), "subprocess returned error");
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
m_childpid = 0;
|
||||
}
|
||||
|
||||
m_read_task.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the header data from the file.
|
||||
*/
|
||||
osmium::io::Header header() const {
|
||||
return m_input->header();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next buffer from the input. An invalid buffer signals
|
||||
* end-of-file. Do not call read() after the end-of-file.
|
||||
*
|
||||
* @returns Buffer.
|
||||
* @throws Some form of std::runtime_error if there is an error.
|
||||
*/
|
||||
osmium::memory::Buffer read() {
|
||||
// If an exception happened in the input thread, re-throw
|
||||
// it in this (the main) thread.
|
||||
m_read_task.check_for_exception();
|
||||
|
||||
if (m_read_which_entities == osmium::osm_entity_bits::nothing) {
|
||||
// If the caller didn't want anything but the header, it will
|
||||
// always get an empty buffer here.
|
||||
return osmium::memory::Buffer();
|
||||
}
|
||||
return m_input->read();
|
||||
}
|
||||
|
||||
}; // class Reader
|
||||
|
||||
/**
|
||||
* Read contents of the given file into a buffer in one go. Takes
|
||||
* the same arguments as any of the Reader constructors.
|
||||
*
|
||||
* The buffer can take up quite a lot of memory, so don't do this
|
||||
* unless you are working with small OSM files and/or have lots of
|
||||
* RAM.
|
||||
*/
|
||||
template <class... TArgs>
|
||||
osmium::memory::Buffer read_file(TArgs&&... args) {
|
||||
osmium::memory::Buffer buffer(1024*1024, osmium::memory::Buffer::auto_grow::yes);
|
||||
|
||||
Reader reader(std::forward<TArgs>(args)...);
|
||||
while (osmium::memory::Buffer read_buffer = reader.read()) {
|
||||
buffer.add_buffer(read_buffer);
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_READER_HPP
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
#ifndef OSMIUM_IO_READER_ITERATOR_HPP
|
||||
#define OSMIUM_IO_READER_ITERATOR_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/reader.hpp>
|
||||
#include <osmium/io/input_iterator.hpp>
|
||||
|
||||
namespace std {
|
||||
|
||||
inline osmium::io::InputIterator<osmium::io::Reader> begin(osmium::io::Reader& reader) {
|
||||
return osmium::io::InputIterator<osmium::io::Reader>(reader);
|
||||
}
|
||||
|
||||
inline osmium::io::InputIterator<osmium::io::Reader> end(osmium::io::Reader&) {
|
||||
return osmium::io::InputIterator<osmium::io::Reader>();
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // OSMIUM_IO_READER_ITERATOR_HPP
|
||||
Vendored
-142
@@ -1,142 +0,0 @@
|
||||
#ifndef OSMIUM_IO_WRITER_HPP
|
||||
#define OSMIUM_IO_WRITER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/read_write.hpp>
|
||||
#include <osmium/io/detail/write_thread.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/io/overwrite.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/thread/checked_task.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
/**
|
||||
* This is the user-facing interface for writing OSM files. Instantiate
|
||||
* an object of this class with a file name or osmium::io::File object
|
||||
* and optionally the data for the header and then call operator() on it
|
||||
* to write Buffers. Call close() to finish up.
|
||||
*/
|
||||
class Writer {
|
||||
|
||||
osmium::io::File m_file;
|
||||
|
||||
std::unique_ptr<osmium::io::detail::OutputFormat> m_output;
|
||||
osmium::io::detail::data_queue_type m_output_queue {};
|
||||
|
||||
std::unique_ptr<osmium::io::Compressor> m_compressor;
|
||||
|
||||
osmium::thread::CheckedTask<detail::WriteThread> m_write_task;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The constructor of the Writer object opens a file and writes the
|
||||
* header to it.
|
||||
*
|
||||
* @param file File (contains name and format info) to open.
|
||||
* @param header Optional header data. If this is not given sensible
|
||||
* defaults will be used. See the default constructor
|
||||
* of osmium::io::Header for details.
|
||||
* @param allow_overwrite Allow overwriting of existing file? Can be
|
||||
* osmium::io::overwrite::allow or osmium::io::overwrite::no+
|
||||
* (default).
|
||||
*
|
||||
* @throws std::runtime_error If the file could not be opened.
|
||||
* @throws std::system_error If the file could not be opened.
|
||||
*/
|
||||
explicit Writer(const osmium::io::File& file, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
|
||||
m_file(file),
|
||||
m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
|
||||
m_compressor(osmium::io::CompressionFactory::instance().create_compressor(file.compression(), osmium::io::detail::open_for_writing(m_file.filename(), allow_overwrite))),
|
||||
m_write_task(m_output_queue, m_compressor.get()) {
|
||||
m_output->write_header(header);
|
||||
}
|
||||
|
||||
explicit Writer(const std::string& filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
|
||||
Writer(osmium::io::File(filename), header, allow_overwrite) {
|
||||
}
|
||||
|
||||
explicit Writer(const char* filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
|
||||
Writer(osmium::io::File(filename), header, allow_overwrite) {
|
||||
}
|
||||
|
||||
Writer(const Writer&) = delete;
|
||||
Writer& operator=(const Writer&) = delete;
|
||||
|
||||
~Writer() {
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write contents of a buffer to the output file.
|
||||
*
|
||||
* @throws Some form of std::runtime_error when there is a problem.
|
||||
*/
|
||||
void operator()(osmium::memory::Buffer&& buffer) {
|
||||
m_write_task.check_for_exception();
|
||||
if (buffer.committed() > 0) {
|
||||
m_output->write_buffer(std::move(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush writes to output file and close it. If you do not
|
||||
* call this, the destructor of Writer will also do the same
|
||||
* thing. But because this call might thrown an exception,
|
||||
* it is better to call close() explicitly.
|
||||
*
|
||||
* @throws Some form of std::runtime_error when there is a problem.
|
||||
*/
|
||||
void close() {
|
||||
m_output->close();
|
||||
m_write_task.close();
|
||||
}
|
||||
|
||||
}; // class Writer
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_IO_WRITER_HPP
|
||||
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
#ifndef OSMIUM_IO_XML_INPUT_HPP
|
||||
#define OSMIUM_IO_XML_INPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/reader.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/xml_input_format.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_XML_INPUT_HPP
|
||||
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
#ifndef OSMIUM_IO_XML_OUTPUT_HPP
|
||||
#define OSMIUM_IO_XML_OUTPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/io/writer.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/xml_output_format.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_XML_OUTPUT_HPP
|
||||
Reference in New Issue
Block a user