added encoding/Base64

This commit is contained in:
lganzzzo 2018-07-08 18:57:43 +03:00
parent 5957798e0e
commit a512c7360a
2 changed files with 299 additions and 0 deletions

191
encoding/Base64.cpp Normal file
View File

@ -0,0 +1,191 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi, <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#include "Base64.hpp"
namespace oatpp { namespace encoding {
v_char8 Base64::getAlphabetCharIndex(v_char8 a, const char* auxiliaryChars) {
if(a >= 'A' && a <='Z') {
return a - 'A';
}
if(a >= 'a' && a <='z') {
return a - 'a' + 26;
}
if(a >= '0' && a <='9') {
return a - '0' + 52;
}
if(a == auxiliaryChars[0]) {
return 62;
}
if(a == auxiliaryChars[1]) {
return 63;
}
return 255;
}
v_int32 Base64::calcEncodedStringSize(v_int32 size) {
v_int32 size3 = size / 3;
v_int32 rSize = size3 * 3;
if(rSize < size){
rSize += 4;
}
return rSize + size3; // resultSize = (size3 * 3 + size3) = size3 * 4
}
v_int32 Base64::calcDecodedStringSize(const char* data, v_int32 size, v_int32& base64StrLength, const char* auxiliaryChars) {
base64StrLength = size;
v_char8 auxChar1 = auxiliaryChars[0];
v_char8 auxChar2 = auxiliaryChars[1];
v_char8 paddingChar = auxiliaryChars[2];
v_int32 i = 0;
while (i < size) {
v_char8 a = data[i];
bool isValidChar = (a >= 'A' && a <='Z') || (a >= 'a' && a <='z') || (a >= '0' && a <='9') || (a == auxChar1) || (a == auxChar2);
if(!isValidChar) {
if(a == paddingChar){
base64StrLength = i;
break;
}
return -1;
}
i++;
}
v_int32 size4 = i >> 2;
v_int32 size4d = i - (size4 << 2);
v_int32 resultSize = size4 * 3;
if(size4d > 0) {
resultSize += size4d - 1;
}
return resultSize;
}
bool Base64::isBase64String(const char* data, v_int32 size, const char* auxiliaryChars) {
v_int32 base64StrLength;
return (calcDecodedStringSize(data, size, base64StrLength, auxiliaryChars) >= 0);
}
oatpp::String Base64::encode(const void* data, v_int32 size, const char* alphabet) {
auto resultSize = calcEncodedStringSize(size);
auto result = oatpp::String(resultSize);
p_char8 bdata = (p_char8) data;
p_char8 resultData = result->getData();
v_int32 pos = 0;
while (pos + 2 < size) {
v_char8 b0 = bdata[pos];
v_char8 b1 = bdata[pos + 1];
v_char8 b2 = bdata[pos + 2];
resultData[0] = alphabet[(b0 & 252) >> 2];
resultData[1] = alphabet[((b0 & 3) << 4) | ((b1 >> 4) & 15)];
resultData[2] = alphabet[((b1 & 15) << 2) | ((b2 >> 6) & 3)];
resultData[3] = alphabet[(b2 & 63)];
resultData += 4;
pos += 3;
}
if(pos + 1 < size) {
v_char8 b0 = bdata[pos];
v_char8 b1 = bdata[pos + 1];
resultData[0] = alphabet[(b0 & 252) >> 2];
resultData[1] = alphabet[((b0 & 3) << 4) | ((b1 >> 4) & 15)];
resultData[2] = alphabet[((b1 & 15) << 2)];
resultData[3] = alphabet[64];
} else if(pos < size) {
v_char8 b0 = bdata[pos];
resultData[0] = alphabet[(b0 & 252) >> 2];
resultData[1] = alphabet[(b0 & 3) << 4];
resultData[2] = alphabet[64];
resultData[3] = alphabet[64];
}
return result;
}
oatpp::String Base64::encode(const oatpp::String& data, const char* alphabet) {
return encode(data->getData(), data->getSize(), alphabet);
}
oatpp::String Base64::decode(const char* data, v_int32 size, const char* auxiliaryChars) {
v_int32 base64StrLength;
auto resultSize = calcDecodedStringSize(data, size, base64StrLength, auxiliaryChars);
if(resultSize < 0) {
throw DecodingError("Data is no base64 string. Make sure that auxiliaryChars match with encoder alphabet");
}
auto result = oatpp::String(resultSize);
p_char8 resultData = result->getData();
v_int32 pos = 0;
while (pos + 3 < base64StrLength) {
v_char8 b0 = getAlphabetCharIndex(data[pos], auxiliaryChars);
v_char8 b1 = getAlphabetCharIndex(data[pos + 1], auxiliaryChars);
v_char8 b2 = getAlphabetCharIndex(data[pos + 2], auxiliaryChars);
v_char8 b3 = getAlphabetCharIndex(data[pos + 3], auxiliaryChars);
resultData[0] = (b0 << 2) | ((b1 >> 4) & 3);
resultData[1] = ((b1 & 15) << 4) | ((b2 >> 2) & 15);
resultData[2] = ((b2 & 3) << 6) | b3;
resultData += 3;
pos += 4;
}
v_int32 posDiff = base64StrLength - pos;
if(posDiff == 3) {
v_char8 b0 = getAlphabetCharIndex(data[pos], auxiliaryChars);
v_char8 b1 = getAlphabetCharIndex(data[pos + 1], auxiliaryChars);
v_char8 b2 = getAlphabetCharIndex(data[pos + 2], auxiliaryChars);
resultData[0] = (b0 << 2) | ((b1 >> 4) & 3);
resultData[1] = ((b1 & 15) << 4) | ((b2 >> 2) & 15);
} else if(posDiff == 2) {
v_char8 b0 = getAlphabetCharIndex(data[pos], auxiliaryChars);
v_char8 b1 = getAlphabetCharIndex(data[pos + 1], auxiliaryChars);
resultData[0] = (b0 << 2) | ((b1 >> 4) & 3);
}
return result;
}
oatpp::String Base64::decode(const oatpp::String& data, const char* auxiliaryChars) {
return decode((const char*)data->getData(), data->getSize(), auxiliaryChars);
}
}}

108
encoding/Base64.hpp Normal file
View File

@ -0,0 +1,108 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi, <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#ifndef oatpp_encoding_Base64_hpp
#define oatpp_encoding_Base64_hpp
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace encoding {
class Base64 {
public:
class DecodingError : public std::runtime_error {
public:
DecodingError(const char* message)
:std::runtime_error(message)
{}
};
private:
static v_char8 getAlphabetCharIndex(v_char8 a, const char* auxiliaryChars);
public:
/**
* Alphabet is array of 65 chars. 64 chars encoding chars, and 65th padding char
*/
constexpr static const char* ALPHABET_BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
constexpr static const char* ALPHABET_BASE64_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
constexpr static const char* ALPHABET_BASE64_URL_SAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-";
/**
* alphabet auxiliary chars - last 3 chars of alphabet including padding char.
*/
constexpr static const char* ALPHABET_BASE64_AUXILIARY_CHARS = "+/=";
constexpr static const char* ALPHABET_BASE64_URL_AUXILIARY_CHARS = "-_=";
constexpr static const char* ALPHABET_BASE64_URL_SAFE_AUXILIARY_CHARS = "._-";
/**
* Returns size of encoding result of a string of the given size
*/
static v_int32 calcEncodedStringSize(v_int32 size);
/**
* Returns size of decoding result. this method assumes that data passed as a param consists of standard base64 set of chars
* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 and three configurable auxiliary chars.
*
* if data passed is not a base64 string then -1 is returned
*/
static v_int32 calcDecodedStringSize(const char* data, v_int32 size, v_int32& base64StrLength, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);
/**
* return (calcDecodedStringSize(data, size, auxiliaryChars) >= 0);
*/
static bool isBase64String(const char* data, v_int32 size, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);
/**
* encode data as base64 string
*/
static oatpp::String encode(const void* data, v_int32 size, const char* alphabet = ALPHABET_BASE64);
/**
* return encode(data->getData(), data->getSize(), alphabet);
*/
static oatpp::String encode(const oatpp::String& data, const char* alphabet = ALPHABET_BASE64);
/**
* decode() this method assumes that data passed as a param consists of standard base64 set of chars
* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 and three configurable auxiliary chars.
*
* throws DecodingError(). in case invalid char found
*/
static oatpp::String decode(const char* data, v_int32 size, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);
/**
* return decode(data->getData(), data->getSize(), auxiliaryChars);
*/
static oatpp::String decode(const oatpp::String& data, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);
};
}}
#endif /* oatpp_encoding_Base64_hpp */