Răsfoiți Sursa

Implement Base64 decode functionality

Patrick-Christopher Mattulat 2 ani în urmă
părinte
comite
f29a3edaef

+ 8 - 15
include/ls_std/encoding/base64/Base64.hpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2022-01-03
- * Changed:         2022-02-06
+ * Changed:         2022-02-27
  *
  * */
 
@@ -31,18 +31,6 @@ namespace ls_std
 
     private:
 
-      const std::unordered_map<char, uint8_t> decodingTable
-      {
-        {'A', 0}, {'B', 1}, {'C', 2}, {'D', 3}, {'E', 4}, {'F', 5}, {'G', 6}, {'H', 7},
-        {'I', 8}, {'J', 9}, {'K', 10}, {'L', 11}, {'M', 12}, {'N', 13}, {'O', 14}, {'P', 15},
-        {'Q', 16}, {'R', 17}, {'S', 18}, {'T', 19}, {'U', 20}, {'V', 21}, {'W', 22}, {'X', 23},
-        {'Y', 24}, {'Z', 25}, {'a', 26}, {'b', 27}, {'c', 28}, {'d', 29}, {'e', 30}, {'f', 31},
-        {'g', 32}, {'h', 33}, {'i', 34}, {'j', 35}, {'k', 36}, {'l', 37}, {'m', 38}, {'n', 39},
-        {'o', 40}, {'p', 41}, {'q', 42}, {'r', 43}, {'s', 44}, {'t', 45}, {'u', 46}, {'v', 47},
-        {'w', 48}, {'x', 49}, {'y', 50}, {'z', 51}, {'0', 52}, {'1', 53}, {'2', 54}, {'3', 55},
-        {'4', 56}, {'5', 57}, {'6', 58}, {'7', 59}, {'8', 60}, {'9', 61}, {'+', 62}, {'/', 63}
-      };
-
       const std::vector<char> encodingTable
       {
         'A','B','C','D','E','F','G','H',
@@ -55,14 +43,19 @@ namespace ls_std
         '4','5','6','7','8','9','+','/'
       };
 
+      static std::string _decodeByteQuadruple(const std::string& _quadruple);
       static uint8_t _detectInitialShiftNumber(size_t size);
+      static uint32_t _generateBitMask(uint32_t _maskValue, uint8_t _shiftValue);
       std::string _getEncodingFromBitSequence(uint32_t bitSequence, size_t characterSequenceSize);
       static uint32_t _getBitSequenceFromCharacterSequence(const std::string &basicString);
-      char _getCharacterFromLookUpTable(uint8_t byteBuffer, uint8_t shiftByBits);
+      char _getCharacterFromLookUpTable(uint8_t byteBuffer);
       std::string _getEncodingFromByteTriple(const std::string& characterSequence);
       static std::string _getNextByteTriple(const std::string& _sequence, size_t _index);
       static std::string _getNextByteQuadruple(const std::string &_sequence, size_t _index);
-      std::string _getDecodingFromByteQuadruple(std::string _byteQuadruple);
+      static uint32_t _extractBitSequence(uint32_t _bitMask, uint32_t _bitStorage);
+      static void _mergeBitSequence(uint32_t &_bitStorage, const uint32_t &_bitMask);
+      static uint32_t _toBitStorage(const std::string &_quadruple);
+      static std::unordered_map<char, uint8_t> _getDecodingMap();
   };
 }
 

+ 79 - 9
source/ls_std/encoding/base64/Base64.cpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2022-01-03
- * Changed:         2022-02-06
+ * Changed:         2022-02-27
  *
  * */
 
@@ -25,22 +25,61 @@ std::string ls_std::Base64::encode(const std::string &_sequence)
 
 std::string ls_std::Base64::decode(const std::string &_sequence)
 {
-  std::string decodedString, byteQuadruple{};
+  std::string decodedString{};
 
-  for(size_t index = 0 ; index < byteQuadruple.size() ; index += 4)
+  for (int index{} ; index < _sequence.size() ; index += 4)
   {
-    byteQuadruple = ls_std::Base64::_getNextByteQuadruple(_sequence, index);
-    decodedString += ls_std::Base64::_getDecodingFromByteQuadruple(byteQuadruple);
+    std::string quadruple = ls_std::Base64::_getNextByteQuadruple(_sequence, index);
+    decodedString += ls_std::Base64::_decodeByteQuadruple(quadruple);
   }
 
   return decodedString;
 }
 
+std::string ls_std::Base64::_decodeByteQuadruple(const std::string& _quadruple)
+{
+  std::string decodedText{};
+  uint8_t shiftValue = 16;
+  uint32_t bitStorage = ls_std::Base64::_toBitStorage(_quadruple);
+
+  for (uint8_t index = 0; index < ((uint8_t) _quadruple.size() - 1); index++)
+  {
+    uint32_t bitMask = ls_std::Base64::_generateBitMask(255, shiftValue);
+    uint32_t bitSequence = ls_std::Base64::_extractBitSequence(bitMask, bitStorage);
+    bitSequence = bitSequence >> shiftValue;
+
+    decodedText += (char) bitSequence;
+    shiftValue -= 8;
+  }
+
+  return decodedText;
+}
+
 uint8_t ls_std::Base64::_detectInitialShiftNumber(size_t size)
 {
   return size * 8 - 6;
 }
 
+uint32_t ls_std::Base64::_extractBitSequence(uint32_t _bitMask, uint32_t _bitStorage)
+{
+  return _bitStorage & _bitMask;
+}
+
+uint32_t ls_std::Base64::_generateBitMask(uint32_t _maskValue, uint8_t _shiftValue)
+{
+  if(_shiftValue == 0)
+  {
+    return _maskValue;
+  }
+
+  if(_shiftValue < 0)
+  {
+    return _maskValue >> _shiftValue;
+  }
+
+  return _maskValue << _shiftValue;
+}
+
 std::string ls_std::Base64::_getEncodingFromBitSequence(uint32_t bitSequence, size_t characterSequenceSize)
 {
   std::string encodedString{};
@@ -50,7 +89,7 @@ std::string ls_std::Base64::_getEncodingFromBitSequence(uint32_t bitSequence, si
   for (uint8_t index = 0 ; index < 3 ; index++)
   {
     buffer = bitSequence >> shiftByBits;
-    encodedString += this->_getCharacterFromLookUpTable((uint8_t) buffer, shiftByBits);
+    encodedString += this->_getCharacterFromLookUpTable((uint8_t) buffer);
     shiftByBits -= 6;
   }
 
@@ -71,7 +110,7 @@ uint32_t ls_std::Base64::_getBitSequenceFromCharacterSequence(const std::string
   return bits;
 }
 
-char ls_std::Base64::_getCharacterFromLookUpTable(uint8_t byteBuffer, uint8_t shiftByBits)
+char ls_std::Base64::_getCharacterFromLookUpTable(uint8_t byteBuffer)
 {
   std::bitset<8> bitSequence{byteBuffer};
   bitSequence.set(6, false);
@@ -80,6 +119,23 @@ char ls_std::Base64::_getCharacterFromLookUpTable(uint8_t byteBuffer, uint8_t sh
   return this->encodingTable[bitSequence.to_ulong()];
 }
 
+std::unordered_map<char, uint8_t> ls_std::Base64::_getDecodingMap()
+{
+  static std::unordered_map<char, uint8_t> decodingMap =
+      {
+          {'A', 0}, {'B', 1}, {'C', 2}, {'D', 3}, {'E', 4}, {'F', 5}, {'G', 6}, {'H', 7},
+          {'I', 8}, {'J', 9}, {'K', 10}, {'L', 11}, {'M', 12}, {'N', 13}, {'O', 14}, {'P', 15},
+          {'Q', 16}, {'R', 17}, {'S', 18}, {'T', 19}, {'U', 20}, {'V', 21}, {'W', 22}, {'X', 23},
+          {'Y', 24}, {'Z', 25}, {'a', 26}, {'b', 27}, {'c', 28}, {'d', 29}, {'e', 30}, {'f', 31},
+          {'g', 32}, {'h', 33}, {'i', 34}, {'j', 35}, {'k', 36}, {'l', 37}, {'m', 38}, {'n', 39},
+          {'o', 40}, {'p', 41}, {'q', 42}, {'r', 43}, {'s', 44}, {'t', 45}, {'u', 46}, {'v', 47},
+          {'w', 48}, {'x', 49}, {'y', 50}, {'z', 51}, {'0', 52}, {'1', 53}, {'2', 54}, {'3', 55},
+          {'4', 56}, {'5', 57}, {'6', 58}, {'7', 59}, {'8', 60}, {'9', 61}, {'+', 62}, {'/', 63}
+      };
+
+  return decodingMap;
+}
+
 std::string ls_std::Base64::_getEncodingFromByteTriple(const std::string& characterSequence)
 {
   uint32_t bitSequence = ls_std::Base64::_getBitSequenceFromCharacterSequence(characterSequence);
@@ -98,9 +154,23 @@ std::string ls_std::Base64::_getNextByteQuadruple(const std::string &_sequence,
   return _sequence.substr(_index, 4);
 }
 
-std::string ls_std::Base64::_getDecodingFromByteQuadruple(std::string _byteQuadruple)
+void ls_std::Base64::_mergeBitSequence(uint32_t &_bitStorage, const uint32_t &_bitMask)
 {
+  _bitStorage = _bitStorage | _bitMask;
+}
 
+uint32_t ls_std::Base64::_toBitStorage(const std::string &_quadruple)
+{
+  uint32_t bitStorage{};
+  uint8_t letterCounter = 1;
+  std::unordered_map<char, uint8_t> decodingMap = ls_std::Base64::_getDecodingMap();
+
+  for(char letter : _quadruple)
+  {
+    uint32_t bitMask = ls_std::Base64::_generateBitMask(decodingMap[(char) letter], (4 - letterCounter) * 6); // must be hardcoded - even in case of less than 4 characters, so that conversion is correct
+    ls_std::Base64::_mergeBitSequence(bitStorage, bitMask);
+    ++letterCounter;
+  }
 
-  return std::string();
+  return bitStorage;
 }

+ 4 - 6
test/cases/encoding/base64/Base64Test.cpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2022-01-08
- * Changed:         2022-02-06
+ * Changed:         2022-02-27
  *
  * */
 
@@ -26,9 +26,6 @@ namespace
       {}
   };
 
-  /*
-   * abc -> 01100001 01100010 01100011 -> 6382179
-   * */
   TEST_F(Base64Test, encode)
   {
     ls_std::Base64 base64{};
@@ -40,8 +37,9 @@ namespace
   TEST_F(Base64Test, decode)
   {
     ls_std::Base64 base64{};
-    std::string base64Sequence = "YWJjZA==";
 
-    ASSERT_STREQ("abcd", base64.decode(base64Sequence).c_str());
+    ASSERT_STREQ("abc", base64.decode("YWJj").c_str());
+    ASSERT_STREQ("abcde", base64.decode("YWJjZGU=").c_str());
+    ASSERT_STREQ("Hello C++!", base64.decode("SGVsbG8gQysrIQ==").c_str());
   }
 }