From 33d9b7e86799b5a2082c39d1a3ace651abb1edfb Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Mon, 17 Oct 2016 12:05:29 +0200 Subject: [PATCH] Add base64 encoding layer (issue #272) - Can be attached to any currently open std::ostream. --- applications/test/base64/Make/files | 3 + applications/test/base64/Make/options | 0 .../test/base64/Test-base64Encoding.C | 169 ++++++++++++++++++ src/OpenFOAM/Make/files | 3 + .../db/IOstreams/hashes/base64Layer.C | 168 +++++++++++++++++ .../db/IOstreams/hashes/base64Layer.H | 127 +++++++++++++ 6 files changed, 470 insertions(+) create mode 100644 applications/test/base64/Make/files create mode 100644 applications/test/base64/Make/options create mode 100644 applications/test/base64/Test-base64Encoding.C create mode 100644 src/OpenFOAM/db/IOstreams/hashes/base64Layer.C create mode 100644 src/OpenFOAM/db/IOstreams/hashes/base64Layer.H diff --git a/applications/test/base64/Make/files b/applications/test/base64/Make/files new file mode 100644 index 0000000000..4c6f18ce4c --- /dev/null +++ b/applications/test/base64/Make/files @@ -0,0 +1,3 @@ +Test-base64Encoding.C + +EXE = $(FOAM_USER_APPBIN)/Test-base64Encoding diff --git a/applications/test/base64/Make/options b/applications/test/base64/Make/options new file mode 100644 index 0000000000..e69de29bb2 diff --git a/applications/test/base64/Test-base64Encoding.C b/applications/test/base64/Test-base64Encoding.C new file mode 100644 index 0000000000..478a1d9848 --- /dev/null +++ b/applications/test/base64/Test-base64Encoding.C @@ -0,0 +1,169 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM 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 General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +Application + Test-base64Encoding + +Description + Test base64 encoding layer. + + Target values generated with "base64 encode ..." in Google. + A simple independent source for comparison. + +\*---------------------------------------------------------------------------*/ + +#include "base64Layer.H" +#include "List.H" +#include "Pair.H" + +#include +#include + +using namespace Foam; + +bool test(const Pair& unit) +{ + const string& input = unit.first(); + const string& expected = unit.second(); + + std::ostringstream os; + + base64Layer b64(os); + b64.write(input.data(), input.size()); + b64.close(); + + const string encoded = os.str(); + + Info<< input << nl; + + if (encoded == expected) + { + Info<< " encoded: " << encoded << " (OK)" << nl + << endl; + return true; + } + else + { + Info<< " encoded: " << encoded << " (ERROR)" << nl + << " expected: " << expected << nl + << endl; + + return false; + } +} + + +bool test(std::initializer_list> list) +{ + bool good = true; + + for (const Pair& t : list) + { + good = test(t) && good; + } + + return good; +} + + +bool test(const UList>& list) +{ + bool good = true; + + for (const Pair& t : list) + { + good = test(t) && good; + } + + return good; +} + + +void testMixed(std::ostream& os, const UList>& list) +{ + base64Layer b64(os); + + os << "" << nl; + + int i=0; + for (const Pair& t : list) + { + const string& input = t.first(); + + os << "" << nl; + os << " "; + + b64.write(input.data(), input.size()); + b64.close(); + + os << nl + << "" << nl; + } + + os << "" << nl + << nl; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +int main(int argc, char * argv[]) +{ + Info<< "Test base64 encode layer" << nl << endl; + + List> testList + { + { + "abcdef", // 6 input, 8 output + "YWJjZGVm" + }, + { + "OpenFOAM", + "T3BlbkZPQU0=" + }, + { + "OpenFOAM: The Open Source CFD Toolbox", + "T3BlbkZPQU06IFRoZSBPcGVuIFNvdXJjZSBDRkQgVG9vbGJveA==" + } + }; + + + bool good = test(testList); + + + // Test mixing output + testMixed(std::cout, testList); + + if (good) + { + Info<< "All tests passed" << endl; + return 0; + } + else + { + Info<< "One or more tests failed" << endl; + return 1; + } +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index 13a9595fcf..8b6be8d895 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -144,6 +144,9 @@ $(Sstreams)/SstreamsPrint.C $(Sstreams)/readHexLabel.C $(Sstreams)/prefixOSstream.C +hashes = $(Streams)/hashes +$(hashes)/base64Layer.C + gzstream = $(Streams)/gzstream $(gzstream)/gzstream.C diff --git a/src/OpenFOAM/db/IOstreams/hashes/base64Layer.C b/src/OpenFOAM/db/IOstreams/hashes/base64Layer.C new file mode 100644 index 0000000000..f1123f7519 --- /dev/null +++ b/src/OpenFOAM/db/IOstreams/hashes/base64Layer.C @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM 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 General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +\*---------------------------------------------------------------------------*/ + +#include "base64Layer.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +//! \cond fileScope +//- The characters used for base-64 +static const unsigned char base64Chars[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; +//! \endcond + + +// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // + +inline unsigned char Foam::base64Layer::encode0() +{ + // Top 6 bits of char0 + return base64Chars[((group_[0] & 0xFC) >> 2)]; +} + +inline unsigned char Foam::base64Layer::encode1() +{ + // Bottom 2 bits of char0, Top 4 bits of char1 + return base64Chars[((group_[0] & 0x03) << 4) | ((group_[1] & 0xF0) >> 4)]; +} + +inline unsigned char Foam::base64Layer::encode2() +{ + // Bottom 4 bits of char1, Top 2 bits of char2 + return base64Chars[((group_[1] & 0x0F) << 2) | ((group_[2] & 0xC0) >> 6)]; +} + +inline unsigned char Foam::base64Layer::encode3() +{ + // Bottom 6 bits of char2 + return base64Chars[(group_[2] & 0x3F)]; +} + + +void Foam::base64Layer::add(char c) +{ + group_[groupLen_++] = static_cast(c); + if (groupLen_ == 3) + { + unsigned char out[4]; + + out[0] = encode0(); + out[1] = encode1(); + out[2] = encode2(); + out[3] = encode3(); + os_.write(reinterpret_cast(out), 4); + + groupLen_ = 0; + } + + dirty_ = true; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::base64Layer::base64Layer(std::ostream& os) +: + os_(os), + group_(), + groupLen_(0), + dirty_(false) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // +Foam::base64Layer::~base64Layer() +{ + close(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::base64Layer::write(const char* s, std::streamsize n) +{ + for (std::streamsize i=0; i < n; ++i) + { + add(s[i]); + } +} + + +void Foam::base64Layer::reset() +{ + groupLen_ = 0; + dirty_ = false; +} + + +bool Foam::base64Layer::close() +{ + if (!dirty_) + { + return false; + } + + unsigned char out[4]; + if (groupLen_ == 1) + { + group_[1] = 0; + + out[0] = encode0(); + out[1] = encode1(); + out[2] = '='; + out[3] = '='; + os_.write(reinterpret_cast(out), 4); + } + else if (groupLen_ == 2) + { + group_[2] = 0; + + out[0] = encode0(); + out[1] = encode1(); + out[2] = encode2(); + out[3] = '='; + os_.write(reinterpret_cast(out), 4); + } + + // group-length == 0 (no content) + // group-length == 3 is not possible, already reset in add() + + groupLen_ = 0; + dirty_ = false; + + return true; +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/db/IOstreams/hashes/base64Layer.H b/src/OpenFOAM/db/IOstreams/hashes/base64Layer.H new file mode 100644 index 0000000000..9aa4bc8d79 --- /dev/null +++ b/src/OpenFOAM/db/IOstreams/hashes/base64Layer.H @@ -0,0 +1,127 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM 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 General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +Class + base64Layer + +Description + An output filter layer to write base-64 encoded content. + + Base64 encoding accoding to RFC 4648 specification + (https://tools.ietf.org/html/rfc4648#page-5). + It is the obligation of the caller to avoid using normal output + while the base-64 encoding layer is actively being used. + +SourceFiles + base64Layer.C + +\*---------------------------------------------------------------------------*/ + +#ifndef base64Layer_H +#define base64Layer_H + +#include + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class base64Layer Declaration +\*---------------------------------------------------------------------------*/ + +class base64Layer +{ + // Private data + + //- The output stream for the layer + std::ostream& os_; + + //- Buffer of characters to encode + unsigned char group_[3]; + + //- Current length of the encode buffer + unsigned char groupLen_; + + //- Track if anything has been encoded. + bool dirty_; + + + // Private Member Functions + + inline unsigned char encode0(); + inline unsigned char encode1(); + inline unsigned char encode2(); + inline unsigned char encode3(); + + //- Disallow default bitwise copy construct + base64Layer(const base64Layer&) = delete; + + //- Disallow default bitwise assignment + void operator=(const base64Layer&) = delete; + + +protected: + + // Protected Member Functions + + //- Add a character to the group, outputting when the group is full. + void add(char c); + + +public: + + // Constructors + + //- Construct and attach to an output stream + base64Layer(std::ostream&); + + + //- Destructor + ~base64Layer(); + + + // Member Functions + + //- Encode the character sequence, writing when possible. + void write(const char* s, std::streamsize n); + + //- Restart a new encoding sequence. + void reset(); + + //- End the encoding sequence, padding the final characters with '='. + // Return false if no encoding layer was actually used. + bool close(); + +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* //