diff --git a/src/Base/Base64.cpp b/src/Base/Base64.cpp index ab45e70e30..4e76b4b4e5 100644 --- a/src/Base/Base64.cpp +++ b/src/Base/Base64.cpp @@ -24,29 +24,28 @@ freely, subject to the following restrictions: René Nyffenegger rene.nyffenegger@adp-gmbh.ch -Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com) +Additional code Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com) +* Added support of in-line transformation using boost iostream for memory efficiency -* Added support of in-line transformation using boost iostream for memory - efficiency */ #include "PreCompiled.h" #ifndef _PreComp_ -#include #include #endif #include "Base64.h" +// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) -static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; +static const std::array base64_chars {"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"}; -const signed char* Base::base64_decode_table() +std::array Base::base64_decode_table() { - static const signed char _table[] = { + static std::array _table = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -1, -2, -1, -1, // 0-15 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47 @@ -70,30 +69,30 @@ const signed char* Base::base64_decode_table() std::size_t Base::base64_encode(char* out, void const* in, std::size_t in_len) { char* ret = out; - unsigned char const* bytes_to_encode = reinterpret_cast(in); - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; + auto const* bytes_to_encode = reinterpret_cast(in); // NOLINT + int char3 {0}; + int char4 {}; + std::array char_array_3{}; + std::array char_array_4{}; - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { + while ((in_len--) != 0U) { + char_array_3[char3++] = *(bytes_to_encode++); + if (char3 == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; - for (i = 0; (i < 4); i++) { - *ret++ = base64_chars[char_array_4[i]]; + for (char3 = 0; (char3 < 4); char3++) { + *ret++ = base64_chars[char_array_4[char3]]; } - i = 0; + char3 = 0; } } - if (i) { - for (j = i; j < 3; j++) { - char_array_3[j] = '\0'; + if (char3 != 0) { + for (char4 = char3; char4 < 3; char4++) { + char_array_3[char4] = '\0'; } char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; @@ -101,11 +100,11 @@ std::size_t Base::base64_encode(char* out, void const* in, std::size_t in_len) char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; - for (j = 0; (j < i + 1); j++) { - *ret++ = base64_chars[char_array_4[j]]; + for (char4 = 0; (char4 < char3 + 1); char4++) { + *ret++ = base64_chars[char_array_4[char4]]; } - while ((i++ < 3)) { + while ((char3++ < 3)) { *ret++ = '='; } } @@ -116,47 +115,50 @@ 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) { - unsigned char* out = reinterpret_cast(_out); + auto* out = reinterpret_cast(_out); // NOLINT unsigned char* ret = out; char const* input = in; - int i = 0; - int j = 0; - unsigned char char_array_4[4], char_array_3[3]; + int byteCounter1 {0}; + int byteCounter2 {}; + std::array char_array_4{}; + std::array char_array_3{}; - static const signed char* table = base64_decode_table(); + static auto table = base64_decode_table(); - while (in_len-- && *in != '=') { - const signed char v = table[(int)(*in++)]; - if (v < 0) { + while (((in_len--) != 0U) && *in != '=') { + const signed char lookup = table[static_cast(*in++)]; + if (lookup < 0) { break; } - char_array_4[i++] = (unsigned char)v; - if (i == 4) { + char_array_4[byteCounter1++] = (unsigned char)lookup; + if (byteCounter1 == 4) { char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (i = 0; (i < 3); i++) { - *ret++ = char_array_3[i]; + for (byteCounter1 = 0; (byteCounter1 < 3); byteCounter1++) { + *ret++ = char_array_3[byteCounter1]; } - i = 0; + byteCounter1 = 0; } } - if (i) { - for (j = i; j < 4; j++) { - char_array_4[j] = 0; + if (byteCounter1 != 0) { + for (byteCounter2 = byteCounter1; byteCounter2 < 4; byteCounter2++) { + char_array_4[byteCounter2] = 0; } char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (j = 0; (j < i - 1); j++) { - *ret++ = char_array_3[j]; + for (byteCounter2 = 0; (byteCounter2 < byteCounter1 - 1); byteCounter2++) { + *ret++ = char_array_3[byteCounter2]; } } 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) diff --git a/src/Base/Base64.h b/src/Base/Base64.h index 30a0ec604b..e41bdddd04 100644 --- a/src/Base/Base64.h +++ b/src/Base/Base64.h @@ -31,6 +31,7 @@ Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com) #ifndef BASE_BASE64_H #define BASE_BASE64_H +#include #include #include #include @@ -39,6 +40,10 @@ Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com) #include #include +#include "FCGlobal.h" + +// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index, cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + namespace Base { @@ -47,6 +52,8 @@ 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 inline std::size_t base64_encode_size(std::size_t len) @@ -76,7 +83,7 @@ BaseExport std::size_t base64_encode(char* out, void const* in, std::size_t len) * data. White space (space, tab, vtab, CR and LF) characters are mapped * to -2. Other invalid characters are mapped to -1. */ -BaseExport const signed char* base64_decode_table(); +BaseExport std::array base64_decode_table(); /** Decode the input base64 string into binary data * @param out: output buffer with minimum size of base64_encode(len) @@ -136,25 +143,25 @@ inline std::size_t base64_decode(T& out, char const* in, std::size_t len) /** Decode base64 string into binary data * @param out: output binary data. Note that the data is not cleared before * adding new content. - * @param s: input base64 string + * @param str: input base64 string * @return Return the processed input length. Compare this with the * argument \c len to check for error. */ template -inline std::size_t base64_decode(T& out, std::string const& s) +inline std::size_t base64_decode(T& out, std::string const& str) { - return base64_decode(out, s.c_str(), s.size()); + return base64_decode(out, str.c_str(), str.size()); } /** Decode base64 string into binary data * @param out adding new content. - * @param s: input base64 string + * @param str: input base64 string * @return Return the decoded binary data. */ -inline std::string base64_decode(std::string const& s) +inline std::string base64_decode(std::string const& str) { std::string out; - base64_decode(out, s.c_str(), s.size()); + base64_decode(out, str.c_str(), str.size()); return out; } @@ -167,7 +174,7 @@ namespace bio = boost::iostreams; struct base64_encoder { - typedef char char_type; + using char_type = char; struct category: bio::multichar_output_filter_tag, bio::closable_tag, bio::optimally_buffered_tag @@ -184,16 +191,16 @@ struct base64_encoder std::streamsize optimal_buffer_size() const { - return base64_decode_size(line_size); + return static_cast(base64_decode_size(line_size)); } template void close(Device& dev) { if (pending_size) { - base64_encode(buffer, pending, pending_size); + base64_encode(buffer, pending.data(), pending_size); } - if (buffer.size()) { + if (!buffer.empty()) { bio::write(dev, buffer.c_str(), buffer.size()); if (line_size) { bio::put(dev, '\n'); @@ -206,27 +213,28 @@ struct base64_encoder } template - std::streamsize write(Device& dev, const char_type* s, std::streamsize n) + std::streamsize write(Device& dev, const char_type* str, std::streamsize n) { std::streamsize res = n; - if (pending_size) { + if (pending_size > 0) { while (n && pending_size < 3) { - pending[pending_size++] = *s++; + pending[pending_size] = *str++; + ++pending_size; --n; } if (pending_size != 3) { return res; } - base64_encode(buffer, pending, 3); + base64_encode(buffer, pending.data(), 3); } pending_size = n % 3; n = n / 3 * 3; - base64_encode(buffer, s, n); - s += n; + base64_encode(buffer, str, n); + str += n; for (unsigned i = 0; i < pending_size; ++i) { - pending[i] = s[i]; + pending[i] = str[i]; } const char* buf = buffer.c_str(); @@ -250,7 +258,7 @@ struct base64_encoder std::size_t line_size; std::size_t pos = 0; std::size_t pending_size = 0; - unsigned char pending[3]; + std::array pending {}; std::string buffer; }; @@ -261,7 +269,7 @@ struct base64_encoder struct base64_decoder { - typedef char char_type; + using char_type = char; struct category: bio::multichar_input_filter_tag, bio::optimally_buffered_tag { }; @@ -278,13 +286,15 @@ struct base64_decoder std::streamsize optimal_buffer_size() const { - return base64_encode_size(line_size != 0U ? line_size : 1024); + 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* s, std::streamsize n) + std::streamsize read(Device& dev, char_type* str, std::streamsize n) { - static const signed char* table = base64_decode_table(); + static auto table = base64_decode_table(); if (!n) { return 0; @@ -294,7 +304,7 @@ struct base64_decoder for (;;) { while (pending_out < out_count) { - *s++ = char_array_3[pending_out++]; + *str++ = char_array_3[pending_out++]; ++count; if (--n == 0) { return count; @@ -306,8 +316,8 @@ struct base64_decoder } for (;;) { - int d = bio::get(dev); - if (d < 0) { + int newChar = bio::get(dev); + if (newChar < 0) { eof = true; if (pending_in <= 1) { if (pending_in == 1 && errHandling == Base64ErrorHandling::throws) { @@ -319,21 +329,23 @@ struct base64_decoder pending_in = 4; } else { - signed char c = table[d]; - if (c < 0) { - if (c == -2 || errHandling == Base64ErrorHandling::silent) { + 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)c; + char_array_4[pending_in++] = (char)decodedChar; } if (pending_in == 4) { pending_out = pending_in = 0; - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = - ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + 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; } } @@ -342,10 +354,10 @@ struct base64_decoder std::size_t line_size; std::uint8_t pending_in = 0; - char char_array_4[4]; + std::array char_array_4 {}; std::uint8_t pending_out = 3; std::uint8_t out_count = 3; - char char_array_3[3]; + std::array char_array_3 {}; Base64ErrorHandling errHandling; bool eof = false; }; @@ -358,13 +370,13 @@ struct base64_decoder * @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 = 80) +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* f = static_cast(res.get()); - f->push(base64_encoder(line_size)); - f->push(out); + auto* filteringStream = dynamic_cast(res.get()); + filteringStream->push(base64_encoder(line_size)); + filteringStream->push(out); return res; } @@ -376,13 +388,13 @@ inline std::unique_ptr create_base64_encoder(std::ostream& out, * @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 = 80) +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); - bio::filtering_ostream* f = static_cast(res.get()); - f->push(base64_encoder(line_size)); - f->push(bio::file_sink(filepath)); + auto* filteringStream = dynamic_cast(res.get()); + filteringStream->push(base64_encoder(line_size)); + filteringStream->push(bio::file_sink(filepath)); return res; } @@ -398,13 +410,13 @@ inline std::unique_ptr create_base64_encoder(const std::string& fi */ inline std::unique_ptr create_base64_decoder(std::istream& in, - std::size_t line_size = 80, + std::size_t line_size = base64DefaultBufferSize, Base64ErrorHandling errHandling = Base64ErrorHandling::silent) { std::unique_ptr res(new bio::filtering_istream); - bio::filtering_istream* f = static_cast(res.get()); - f->push(base64_decoder(line_size, errHandling)); - f->push(in); + auto* filteringStream = dynamic_cast(res.get()); + filteringStream->push(base64_decoder(line_size, errHandling)); + filteringStream->push(in); return res; } @@ -424,16 +436,18 @@ create_base64_decoder(std::istream& in, */ inline std::unique_ptr create_base64_decoder(const std::string& filepath, - std::size_t line_size = 80, + std::size_t line_size = base64DefaultBufferSize, Base64ErrorHandling errHandling = Base64ErrorHandling::silent) { std::unique_ptr res(new bio::filtering_istream); - auto* f = static_cast(res.get()); - f->push(base64_decoder(line_size, errHandling)); - f->push(bio::file_source(filepath)); + 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 diff --git a/src/Base/FileInfo.h b/src/Base/FileInfo.h index e8597232b5..cf29077ea4 100644 --- a/src/Base/FileInfo.h +++ b/src/Base/FileInfo.h @@ -41,7 +41,6 @@ enum class CharStreamFormat { Raw, Base64Encoded }; -static constexpr int base64LineWidth {80}; /** File name unification * This class handles everything related to file names diff --git a/src/Base/Reader.cpp b/src/Base/Reader.cpp index 83caec65fe..afa4a3358c 100644 --- a/src/Base/Reader.cpp +++ b/src/Base/Reader.cpp @@ -372,7 +372,7 @@ std::istream& Base::XMLReader::beginCharStream(CharStreamFormat format) CharStream = std::make_unique(); auto* filteringStream = dynamic_cast(CharStream.get()); if(format == CharStreamFormat::Base64Encoded) { - filteringStream->push(base64_decoder(Base::base64LineWidth, Base64ErrorHandling::silent)); + filteringStream->push(base64_decoder(Base::base64DefaultBufferSize, Base64ErrorHandling::silent)); } filteringStream->push(boost::ref(*this)); return *CharStream; diff --git a/src/Base/Writer.cpp b/src/Base/Writer.cpp index 4ecc1ad370..9f51e1473d 100644 --- a/src/Base/Writer.cpp +++ b/src/Base/Writer.cpp @@ -90,7 +90,7 @@ std::ostream& Writer::beginCharStream(CharStreamFormat format) } charStreamFormat = format; if(format == CharStreamFormat::Base64Encoded) { - CharStream = create_base64_encoder(Stream(), Base::base64LineWidth); + CharStream = create_base64_encoder(Stream(), Base::base64DefaultBufferSize); } else { Stream() << "();