| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #ifndef FREECAD_BASE_BASE64FILTER_H |
| | #define FREECAD_BASE_BASE64FILTER_H |
| |
|
| |
|
| | #include "Base64.h" |
| | #include "FCGlobal.h" |
| |
|
| | #include <boost/iostreams/concepts.hpp> |
| | #include <boost/iostreams/device/file.hpp> |
| | #include <boost/iostreams/filtering_stream.hpp> |
| | #include <boost/iostreams/operations.hpp> |
| |
|
| |
|
| | |
| | |
| | |
| |
|
| | namespace Base |
| | { |
| |
|
| | namespace bio = boost::iostreams; |
| |
|
| | enum class Base64ErrorHandling |
| | { |
| | throws, |
| | silent |
| | }; |
| | static constexpr int base64DefaultBufferSize {80}; |
| |
|
| | |
| | |
| | |
| | |
| | struct base64_encoder |
| | { |
| |
|
| | using char_type = char; |
| | struct category: bio::multichar_output_filter_tag, bio::closable_tag, bio::optimally_buffered_tag |
| | { |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | explicit base64_encoder(std::size_t line_size) |
| | : line_size(line_size) |
| | {} |
| |
|
| | std::streamsize optimal_buffer_size() const |
| | { |
| | static constexpr int defaultBufferSize {1024}; |
| | return static_cast<std::streamsize>( |
| | base64_encode_size(line_size != 0U ? line_size : defaultBufferSize) |
| | ); |
| | } |
| |
|
| | template<typename Device> |
| | void close(Device& dev) |
| | { |
| | if (pending_size) { |
| | base64_encode(buffer, pending.data(), pending_size); |
| | } |
| | if (!buffer.empty()) { |
| | bio::write(dev, buffer.c_str(), buffer.size()); |
| | if (line_size) { |
| | bio::put(dev, '\n'); |
| | } |
| | buffer.clear(); |
| | } |
| | else if (pos && line_size) { |
| | bio::put(dev, '\n'); |
| | } |
| | } |
| |
|
| | template<typename Device> |
| | std::streamsize write(Device& dev, const char_type* str, std::streamsize n) |
| | { |
| | std::streamsize res = n; |
| |
|
| | if (pending_size > 0) { |
| | while (n && pending_size < 3) { |
| | pending[pending_size] = *str++; |
| | ++pending_size; |
| | --n; |
| | } |
| | if (pending_size != 3) { |
| | return res; |
| | } |
| |
|
| | base64_encode(buffer, pending.data(), 3); |
| | } |
| | pending_size = n % 3; |
| | n = n / 3 * 3; |
| | base64_encode(buffer, str, n); |
| | str += n; |
| | for (unsigned i = 0; i < pending_size; ++i) { |
| | pending[i] = str[i]; |
| | } |
| |
|
| | const char* buf = buffer.c_str(); |
| | const char* end = buf + buffer.size(); |
| | if (line_size && buffer.size() >= line_size - pos) { |
| | bio::write(dev, buf, line_size - pos); |
| | bio::put(dev, '\n'); |
| | buf += line_size - pos; |
| | pos = 0; |
| | for (; end - buf >= (int)line_size; buf += line_size) { |
| | bio::write(dev, buf, line_size); |
| | bio::put(dev, '\n'); |
| | } |
| | } |
| | pos += end - buf; |
| | bio::write(dev, buf, end - buf); |
| | buffer.clear(); |
| | return n; |
| | } |
| |
|
| | std::size_t line_size; |
| | std::size_t pos = 0; |
| | std::size_t pending_size = 0; |
| | std::array<unsigned char, 3> pending {}; |
| | std::string buffer; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | struct base64_decoder |
| | { |
| |
|
| | using char_type = char; |
| | struct category: bio::multichar_input_filter_tag, bio::optimally_buffered_tag |
| | { |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | base64_decoder(std::size_t line_size, Base64ErrorHandling errHandling) |
| | : line_size(line_size) |
| | , errHandling(errHandling) |
| | {} |
| |
|
| | std::streamsize optimal_buffer_size() const |
| | { |
| | static constexpr int defaultBufferSize {1024}; |
| | return static_cast<std::streamsize>( |
| | base64_encode_size(line_size != 0U ? line_size : defaultBufferSize) |
| | ); |
| | } |
| |
|
| | template<typename Device> |
| | std::streamsize read(Device& dev, char_type* str, std::streamsize n) |
| | { |
| | static auto table = base64_decode_table(); |
| |
|
| | if (!n) { |
| | return 0; |
| | } |
| |
|
| | std::streamsize count = 0; |
| |
|
| | for (;;) { |
| | while (pending_out < out_count) { |
| | *str++ = char_array_3[pending_out++]; |
| | ++count; |
| | if (--n == 0) { |
| | return count; |
| | } |
| | } |
| |
|
| | if (eof) { |
| | return count ? count : -1; |
| | } |
| |
|
| | for (;;) { |
| | int newChar = bio::get(dev); |
| | if (newChar < 0) { |
| | eof = true; |
| | if (pending_in <= 1) { |
| | if (pending_in == 1 && errHandling == Base64ErrorHandling::throws) { |
| | throw BOOST_IOSTREAMS_FAILURE("Unexpected ending of base64 string"); |
| | } |
| | return count ? count : -1; |
| | } |
| | out_count = pending_in - 1; |
| | pending_in = 4; |
| | } |
| | else { |
| | signed char decodedChar = table[newChar]; |
| | if (decodedChar < 0) { |
| | if (decodedChar == -2 || errHandling == Base64ErrorHandling::silent) { |
| | continue; |
| | } |
| | throw BOOST_IOSTREAMS_FAILURE("Invalid character in base64 string"); |
| | } |
| | char_array_4[pending_in++] = (char)decodedChar; |
| | } |
| | if (pending_in == 4) { |
| | pending_out = pending_in = 0; |
| | char_array_3[0] = static_cast<char>( |
| | (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4) |
| | ); |
| | char_array_3[1] = static_cast<char>( |
| | ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2) |
| | ); |
| | char_array_3[2] = static_cast<char>( |
| | ((char_array_4[2] & 0x3) << 6) + char_array_4[3] |
| | ); |
| | break; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | std::size_t line_size; |
| | std::uint8_t pending_in = 0; |
| | std::array<char, 4> char_array_4 {}; |
| | std::uint8_t pending_out = 3; |
| | std::uint8_t out_count = 3; |
| | std::array<char, 3> char_array_3 {}; |
| | Base64ErrorHandling errHandling; |
| | bool eof = false; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | inline std::unique_ptr<std::ostream> create_base64_encoder( |
| | std::ostream& out, |
| | std::size_t line_size = base64DefaultBufferSize |
| | ) |
| | { |
| | std::unique_ptr<std::ostream> res(new bio::filtering_ostream); |
| | auto* filteringStream = dynamic_cast<bio::filtering_ostream*>(res.get()); |
| | filteringStream->push(base64_encoder(line_size)); |
| | filteringStream->push(out); |
| | return res; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | inline std::unique_ptr<std::ostream> create_base64_encoder( |
| | const std::string& filepath, |
| | std::size_t line_size = base64DefaultBufferSize |
| | ) |
| | { |
| | std::unique_ptr<std::ostream> res(new bio::filtering_ostream); |
| | auto* filteringStream = dynamic_cast<bio::filtering_ostream*>(res.get()); |
| | filteringStream->push(base64_encoder(line_size)); |
| | filteringStream->push(bio::file_sink(filepath)); |
| | return res; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | inline std::unique_ptr<std::istream> create_base64_decoder( |
| | std::istream& in, |
| | std::size_t line_size = base64DefaultBufferSize, |
| | Base64ErrorHandling errHandling = Base64ErrorHandling::silent |
| | ) |
| | { |
| | std::unique_ptr<std::istream> res(new bio::filtering_istream); |
| | auto* filteringStream = dynamic_cast<bio::filtering_istream*>(res.get()); |
| | filteringStream->push(base64_decoder(line_size, errHandling)); |
| | filteringStream->push(in); |
| | return res; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | inline std::unique_ptr<std::istream> create_base64_decoder( |
| | const std::string& filepath, |
| | std::size_t line_size = base64DefaultBufferSize, |
| | Base64ErrorHandling errHandling = Base64ErrorHandling::silent |
| | ) |
| | { |
| | std::unique_ptr<std::istream> res(new bio::filtering_istream); |
| | auto* filteringStream = dynamic_cast<bio::filtering_istream*>(res.get()); |
| | filteringStream->push(base64_decoder(line_size, errHandling)); |
| | filteringStream->push(bio::file_source(filepath)); |
| | return res; |
| | } |
| |
|
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | #endif |
| |
|