diff --git a/src/Base/Base64.cpp b/src/Base/Base64.cpp index 4e76b4b4e5..dd426c8c5b 100644 --- a/src/Base/Base64.cpp +++ b/src/Base/Base64.cpp @@ -23,9 +23,9 @@ freely, subject to the following restrictions: René Nyffenegger rene.nyffenegger@adp-gmbh.ch - -Additional code Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com) -* Added support of in-line transformation using boost iostream for memory efficiency +NOTICE: The source code here has been altered from the original to use a provided character buffer +rather than returning a new string for each call. +These modifications are Copyright (c) 2019 Zheng Lei (realthunder.dev@gmail.com) */ #include "PreCompiled.h" @@ -36,7 +36,9 @@ Additional code Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com) #include "Base64.h" -// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) +// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, +// cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, +// readability-magic-numbers) static const std::array base64_chars {"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" @@ -69,11 +71,11 @@ std::array Base::base64_decode_t std::size_t Base::base64_encode(char* out, void const* in, std::size_t in_len) { char* ret = out; - auto const* bytes_to_encode = reinterpret_cast(in); // NOLINT + auto const* bytes_to_encode = reinterpret_cast(in); // NOLINT int char3 {0}; int char4 {}; - std::array char_array_3{}; - std::array char_array_4{}; + std::array char_array_3 {}; + std::array char_array_4 {}; while ((in_len--) != 0U) { char_array_3[char3++] = *(bytes_to_encode++); @@ -115,13 +117,13 @@ std::size_t Base::base64_encode(char* out, void const* in, std::size_t in_len) std::pair Base::base64_decode(void* _out, char const* in, std::size_t in_len) { - auto* out = reinterpret_cast(_out); // NOLINT + auto* out = reinterpret_cast(_out); // NOLINT unsigned char* ret = out; char const* input = in; int byteCounter1 {0}; int byteCounter2 {}; - std::array char_array_4{}; - std::array char_array_3{}; + std::array char_array_4 {}; + std::array char_array_3 {}; static auto table = base64_decode_table(); @@ -161,4 +163,6 @@ Base::base64_decode(void* _out, char const* in, std::size_t in_len) return std::make_pair((std::size_t)(ret - out), (std::size_t)(in - input)); } -// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) +// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, +// cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, +// readability-magic-numbers) diff --git a/src/Base/Base64.h b/src/Base/Base64.h index e41bdddd04..f60a4b5a8c 100644 --- a/src/Base/Base64.h +++ b/src/Base/Base64.h @@ -23,36 +23,28 @@ freely, subject to the following restrictions: René Nyffenegger rene.nyffenegger@adp-gmbh.ch -Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com) -* Added support of in-line transformation using boost iostream for memory - efficiency +NOTICE: The source code here has been altered from the original to use a provided character buffer +rather than returning a new string for each call. +These modifications are Copyright (c) 2019 Zheng Lei (realthunder.dev@gmail.com) */ #ifndef BASE_BASE64_H #define BASE_BASE64_H #include -#include -#include -#include -#include #include #include #include #include "FCGlobal.h" -// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) +// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, +// cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, +// readability-magic-numbers) namespace Base { -enum class Base64ErrorHandling -{ - throws, - silent -}; -static constexpr int base64DefaultBufferSize {80}; static constexpr size_t base64DecodeTableSize {256}; /// Returns the max bytes of a encoded base64 string @@ -165,289 +157,10 @@ inline std::string base64_decode(std::string const& str) return out; } -namespace bio = boost::iostreams; - -/** A base64 encoder that can be used as a boost iostream filter - * - * @sa See create_base64_encoder() for example usage - */ -struct base64_encoder -{ - - using char_type = char; - struct category: bio::multichar_output_filter_tag, - bio::closable_tag, - bio::optimally_buffered_tag - { - }; - - /** Constructor - * @param line_size: line size for the output base64 string, 0 to - * disable segmentation. - */ - base64_encoder(std::size_t line_size) - : line_size(line_size) - {} - - std::streamsize optimal_buffer_size() const - { - return static_cast(base64_decode_size(line_size)); - } - - template - 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 - 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 pending {}; - std::string buffer; -}; - -/** A base64 decoder that can be used as a boost iostream filter - * - * @sa See create_base64_decoder() for example usage - */ -struct base64_decoder -{ - - using char_type = char; - struct category: bio::multichar_input_filter_tag, bio::optimally_buffered_tag - { - }; - - /** Constructor - * @param line_size: line size of the encoded base64 string. This is - * used just as a suggestion for better buffering. - * @param silent: whether to throw on invalid non white space character. - */ - 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( - base64_encode_size(line_size != 0U ? line_size : defaultBufferSize)); - } - - template - 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_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4)); - char_array_3[1] = static_cast(((char_array_4[1] & 0xf) << 4) - + ((char_array_4[2] & 0x3c) >> 2)); - char_array_3[2] = - static_cast(((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_array_4 {}; - std::uint8_t pending_out = 3; - std::uint8_t out_count = 3; - std::array char_array_3 {}; - Base64ErrorHandling errHandling; - bool eof = false; -}; - -/** Create an output stream that transforms the input binary data to base64 strings - * - * @param out: the downstream output stream that will be fed with base64 string - * @param line_size: line size of the base64 string. Zero to disable segmenting. - * - * @return A unique pointer to an output stream that can transforms the - * input binary data to base64 strings. - */ -inline std::unique_ptr -create_base64_encoder(std::ostream& out, std::size_t line_size = base64DefaultBufferSize) -{ - std::unique_ptr res(new bio::filtering_ostream); - auto* filteringStream = dynamic_cast(res.get()); - filteringStream->push(base64_encoder(line_size)); - filteringStream->push(out); - return res; -} - -/** Create an output stream that stores the input binary data to file as base64 strings - * - * @param filename: the output file path - * @param line_size: line size of the base64 string. Zero to disable segmenting. - * - * @return A unique pointer to an output stream that can transforms the - * input binary data to base64 strings. - */ -inline std::unique_ptr -create_base64_encoder(const std::string& filepath, std::size_t line_size = base64DefaultBufferSize) -{ - std::unique_ptr res(new bio::filtering_ostream); - auto* filteringStream = dynamic_cast(res.get()); - filteringStream->push(base64_encoder(line_size)); - filteringStream->push(bio::file_sink(filepath)); - return res; -} - -/** Create an input stream that can transform base64 into binary - * - * @param in: input upstream. - * @param line_size: line size of the encoded base64 string. This is - * used just as a suggestion for better buffering. - * @param silent: whether to throw on invalid non white space character. - * - * @return A unique pointer to an input stream that read from the given - * upstream and transform the read base64 strings into binary data. - */ -inline std::unique_ptr -create_base64_decoder(std::istream& in, - std::size_t line_size = base64DefaultBufferSize, - Base64ErrorHandling errHandling = Base64ErrorHandling::silent) -{ - std::unique_ptr res(new bio::filtering_istream); - auto* filteringStream = dynamic_cast(res.get()); - filteringStream->push(base64_decoder(line_size, errHandling)); - filteringStream->push(in); - return res; -} - -/** Create an input stream that can transform base64 into binary - * - * @param filepath: input file. - * @param ending: optional ending character. If non zero, the filter - * will signal EOF when encounter this character. - * @param putback: if true and the filter read the ending character - * it will put it back into upstream - * @param line_size: line size of the encoded base64 string. This is - * used just as a suggestion for better buffering. - * @param silent: whether to throw on invalid non white space character. - * - * @return A unique pointer to an input stream that read from the given - * file and transform the read base64 strings into binary data. - */ -inline std::unique_ptr -create_base64_decoder(const std::string& filepath, - std::size_t line_size = base64DefaultBufferSize, - Base64ErrorHandling errHandling = Base64ErrorHandling::silent) -{ - std::unique_ptr res(new bio::filtering_istream); - auto* filteringStream = dynamic_cast(res.get()); - filteringStream->push(base64_decoder(line_size, errHandling)); - filteringStream->push(bio::file_source(filepath)); - return res; -} - } // namespace Base -// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) +// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, +// cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, +// readability-magic-numbers) #endif diff --git a/src/Base/Base64Filter.h b/src/Base/Base64Filter.h new file mode 100644 index 0000000000..cdc3374466 --- /dev/null +++ b/src/Base/Base64Filter.h @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2019 Zheng Lei (realthunder.dev@gmail.com) * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_BASE_BASE64FILTER_H +#define FREECAD_BASE_BASE64FILTER_H + + +#include "Base64.h" +#include "FCGlobal.h" + +#include +#include +#include +#include + + +// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, +// cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, +// readability-magic-numbers) + +namespace Base +{ + +namespace bio = boost::iostreams; + +enum class Base64ErrorHandling +{ + throws, + silent +}; +static constexpr int base64DefaultBufferSize {80}; + +/** A base64 encoder that can be used as a boost iostream filter + * + * @sa See create_base64_encoder() for example usage + */ +struct base64_encoder +{ + + using char_type = char; + struct category: bio::multichar_output_filter_tag, + bio::closable_tag, + bio::optimally_buffered_tag + { + }; + + /** Constructor + * @param line_size: line size for the output base64 string, 0 to + * disable segmentation. + */ + 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( + base64_encode_size(line_size != 0U ? line_size : defaultBufferSize)); + } + + template + 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 + 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 pending {}; + std::string buffer; +}; + +/** A base64 decoder that can be used as a boost iostream filter + * + * @sa See create_base64_decoder() for example usage + */ +struct base64_decoder +{ + + using char_type = char; + struct category: bio::multichar_input_filter_tag, bio::optimally_buffered_tag + { + }; + + /** Constructor + * @param line_size: line size of the encoded base64 string. This is + * used just as a suggestion for better buffering. + * @param silent: whether to throw on invalid non white space character. + */ + 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( + base64_encode_size(line_size != 0U ? line_size : defaultBufferSize)); + } + + template + 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_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4)); + char_array_3[1] = static_cast(((char_array_4[1] & 0xf) << 4) + + ((char_array_4[2] & 0x3c) >> 2)); + char_array_3[2] = + static_cast(((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_array_4 {}; + std::uint8_t pending_out = 3; + std::uint8_t out_count = 3; + std::array char_array_3 {}; + Base64ErrorHandling errHandling; + bool eof = false; +}; + +/** Create an output stream that transforms the input binary data to base64 strings + * + * @param out: the downstream output stream that will be fed with base64 string + * @param line_size: line size of the base64 string. Zero to disable segmenting. + * + * @return A unique pointer to an output stream that can transforms the + * input binary data to base64 strings. + */ +inline std::unique_ptr +create_base64_encoder(std::ostream& out, std::size_t line_size = base64DefaultBufferSize) +{ + std::unique_ptr res(new bio::filtering_ostream); + auto* filteringStream = dynamic_cast(res.get()); + filteringStream->push(base64_encoder(line_size)); + filteringStream->push(out); + return res; +} + +/** Create an output stream that stores the input binary data to file as base64 strings + * + * @param filename: the output file path + * @param line_size: line size of the base64 string. Zero to disable segmenting. + * + * @return A unique pointer to an output stream that can transforms the + * input binary data to base64 strings. + */ +inline std::unique_ptr +create_base64_encoder(const std::string& filepath, std::size_t line_size = base64DefaultBufferSize) +{ + std::unique_ptr res(new bio::filtering_ostream); + auto* filteringStream = dynamic_cast(res.get()); + filteringStream->push(base64_encoder(line_size)); + filteringStream->push(bio::file_sink(filepath)); + return res; +} + +/** Create an input stream that can transform base64 into binary + * + * @param in: input upstream. + * @param line_size: line size of the encoded base64 string. This is + * used just as a suggestion for better buffering. + * @param silent: whether to throw on invalid non white space character. + * + * @return A unique pointer to an input stream that read from the given + * upstream and transform the read base64 strings into binary data. + */ +inline std::unique_ptr +create_base64_decoder(std::istream& in, + std::size_t line_size = base64DefaultBufferSize, + Base64ErrorHandling errHandling = Base64ErrorHandling::silent) +{ + std::unique_ptr res(new bio::filtering_istream); + auto* filteringStream = dynamic_cast(res.get()); + filteringStream->push(base64_decoder(line_size, errHandling)); + filteringStream->push(in); + return res; +} + +/** Create an input stream that can transform base64 into binary + * + * @param filepath: input file. + * @param ending: optional ending character. If non zero, the filter + * will signal EOF when encounter this character. + * @param putback: if true and the filter read the ending character + * it will put it back into upstream + * @param line_size: line size of the encoded base64 string. This is + * used just as a suggestion for better buffering. + * @param silent: whether to throw on invalid non white space character. + * + * @return A unique pointer to an input stream that read from the given + * file and transform the read base64 strings into binary data. + */ +inline std::unique_ptr +create_base64_decoder(const std::string& filepath, + std::size_t line_size = base64DefaultBufferSize, + Base64ErrorHandling errHandling = Base64ErrorHandling::silent) +{ + std::unique_ptr res(new bio::filtering_istream); + auto* filteringStream = dynamic_cast(res.get()); + filteringStream->push(base64_decoder(line_size, errHandling)); + filteringStream->push(bio::file_source(filepath)); + return res; +} + +} // namespace Base + +// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, +// cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, +// readability-magic-numbers) + +#endif // FREECAD_BASE_BASE64FILTER_H diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index d73271bed1..4e70b6229d 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -287,6 +287,7 @@ SET(SWIG_HEADERS SET(FreeCADBase_HPP_SRCS Axis.h Base64.h + Base64Filter.h BaseClass.h BindingManager.h Bitmask.h diff --git a/src/Base/Reader.cpp b/src/Base/Reader.cpp index afa4a3358c..932d64aaa7 100644 --- a/src/Base/Reader.cpp +++ b/src/Base/Reader.cpp @@ -32,6 +32,7 @@ #include "Reader.h" #include "Base64.h" +#include "Base64Filter.h" #include "Console.h" #include "InputSource.h" #include "Persistence.h" diff --git a/src/Base/Writer.cpp b/src/Base/Writer.cpp index 9f51e1473d..7d2931544f 100644 --- a/src/Base/Writer.cpp +++ b/src/Base/Writer.cpp @@ -29,6 +29,7 @@ #include "Writer.h" #include "Base64.h" +#include "Base64Filter.h" #include "Exception.h" #include "FileInfo.h" #include "Persistence.h" diff --git a/tests/src/Base/Base64.cpp b/tests/src/Base/Base64.cpp new file mode 100644 index 0000000000..f20b14350d --- /dev/null +++ b/tests/src/Base/Base64.cpp @@ -0,0 +1,91 @@ +/* +Copyright (C) 2004-2008 René Nyffenegger + +This source code is provided 'as-is', without any express or implied +warranty. In no event will the author be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + +3. This notice may not be removed or altered from any source distribution. + +René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +NOTICE: This test has been modified from the original code to remove output to stdout, and to split +the tests into individual parts. + +*/ + +#include "Base/Base64.h" + +#include + +using namespace Base; + +// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) + +TEST(Base64, encode) +{ + const std::string str = "René Nyffenegger\n" + "http://www.renenyffenegger.ch\n" + "passion for data\n"; + + auto encoded = base64_encode(reinterpret_cast(str.c_str()), str.length()); + auto decoded = base64_decode(std::string(encoded)); + + ASSERT_EQ(decoded, str); +} + +TEST(Base64, exactlyFourBytes) +{ + // Test all possibilities of fill bytes (none, one =, two ==) + // References calculated with: https://www.base64encode.org/ + + std::string rest0_original = "abc"; + // std::string rest0_reference = "YWJj"; + + std::string rest0_encoded = + base64_encode(reinterpret_cast(rest0_original.c_str()), + rest0_original.length()); + std::string rest0_decoded = base64_decode(rest0_encoded); + + ASSERT_EQ(rest0_decoded, rest0_original); +} + +TEST(Base64, twoEqualsSignsPadding) +{ + std::string rest1_original = "abcd"; + // std::string rest1_reference = "YWJjZA=="; + + std::string rest1_encoded = + base64_encode(reinterpret_cast(rest1_original.c_str()), + rest1_original.length()); + std::string rest1_decoded = base64_decode(rest1_encoded); + + ASSERT_EQ(rest1_decoded, rest1_original); +} + +TEST(Base64, oneEqualsSignPadding) +{ + std::string rest2_original = "abcde"; + // std::string rest2_reference = "YWJjZGU="; + + std::string rest2_encoded = + base64_encode(reinterpret_cast(rest2_original.c_str()), + rest2_original.length()); + std::string rest2_decoded = base64_decode(rest2_encoded); + + ASSERT_EQ(rest2_decoded, rest2_original); +} + +// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) diff --git a/tests/src/Base/CMakeLists.txt b/tests/src/Base/CMakeLists.txt index fcdb9ee032..307c6c3228 100644 --- a/tests/src/Base/CMakeLists.txt +++ b/tests/src/Base/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources( Tests_run PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Axis.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Base64.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bitmask.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BoundBox.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Builder3D.cpp diff --git a/tests/src/Base/Writer.cpp b/tests/src/Base/Writer.cpp index 139a218c9c..93bc5a0257 100644 --- a/tests/src/Base/Writer.cpp +++ b/tests/src/Base/Writer.cpp @@ -118,7 +118,7 @@ TEST_F(WriterTest, charStream) TEST_F(WriterTest, charStreamBase64Encoded) { // Arrange - auto& stream {_writer.beginCharStream(Base::CharStreamFormat::Base64Encoded)}; + _writer.beginCharStream(Base::CharStreamFormat::Base64Encoded); std::string data {"FreeCAD rocks! 🪨🪨🪨"}; // Act