2023-07-15 12:26:16 +02:00
|
|
|
/*
|
|
|
|
|
* This file is part of the Flowee project
|
|
|
|
|
* Copyright (C) 2009-2010 Satoshi Nakamoto
|
|
|
|
|
* Copyright (C) 2009-2016 The Bitcoin Core developers
|
|
|
|
|
* Copyright (C) 2023 Tom Zander <tom@flowee.org>
|
|
|
|
|
*
|
|
|
|
|
* This program 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.
|
|
|
|
|
*
|
|
|
|
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "StringUtils.h"
|
|
|
|
|
|
|
|
|
|
#include "utilstrencodings.h"
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
2023-07-17 21:02:38 +02:00
|
|
|
std::vector<char> StringUtils::parseHex(const char *string, int size)
|
2023-07-15 12:26:16 +02:00
|
|
|
{
|
2023-07-17 21:02:38 +02:00
|
|
|
const char *end = string + size;
|
2023-07-15 12:26:16 +02:00
|
|
|
std::vector<char> answer;
|
2023-07-17 21:02:38 +02:00
|
|
|
while (string < end) {
|
2023-07-15 12:26:16 +02:00
|
|
|
while (isspace(*string))
|
|
|
|
|
string++;
|
|
|
|
|
signed char c = HexDigit(*string++);
|
|
|
|
|
if (c == (signed char)-1)
|
|
|
|
|
break;
|
|
|
|
|
unsigned char n = (c << 4);
|
|
|
|
|
c = HexDigit(*string++);
|
|
|
|
|
if (c == (signed char)-1)
|
|
|
|
|
break;
|
|
|
|
|
n |= c;
|
|
|
|
|
answer.push_back(n);
|
|
|
|
|
}
|
|
|
|
|
return answer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<char> StringUtils::parseHex(const std::string &source)
|
|
|
|
|
{
|
2023-07-17 21:02:38 +02:00
|
|
|
return parseHex(source.c_str(), source.size());
|
2023-07-15 12:26:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string StringUtils::decodeBase64(const std::string &source)
|
|
|
|
|
{
|
|
|
|
|
std::vector<char> vchRet = decodeBase64(source.c_str());
|
|
|
|
|
if (vchRet.empty())
|
|
|
|
|
return std::string();
|
|
|
|
|
|
|
|
|
|
return std::string((const char*)&vchRet[0], vchRet.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string StringUtils::encodeBase64(const char *source, size_t length)
|
|
|
|
|
{
|
|
|
|
|
static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
|
|
|
|
|
std::string answer;
|
|
|
|
|
answer.reserve((length+2)/3*4);
|
|
|
|
|
|
|
|
|
|
int mode = 0, left = 0;
|
|
|
|
|
const uint8_t *ptr = reinterpret_cast<const uint8_t*>(source);
|
|
|
|
|
const uint8_t *end = ptr + length;
|
|
|
|
|
while (ptr < end) {
|
|
|
|
|
int enc = *(ptr++);
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case 0: // we have no bits
|
|
|
|
|
answer += pbase64[enc >> 2];
|
|
|
|
|
left = (enc & 3) << 4;
|
|
|
|
|
mode = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // we have two bits
|
|
|
|
|
answer += pbase64[left | (enc >> 4)];
|
|
|
|
|
left = (enc & 15) << 2;
|
|
|
|
|
mode = 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: // we have four bits
|
|
|
|
|
answer += pbase64[left | (enc >> 6)];
|
|
|
|
|
answer += pbase64[enc & 63];
|
|
|
|
|
mode = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mode) {
|
|
|
|
|
answer += pbase64[left];
|
|
|
|
|
answer += '=';
|
|
|
|
|
if (mode == 1)
|
|
|
|
|
answer += '=';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return answer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string StringUtils::encodeBase64(const std::string &source)
|
|
|
|
|
{
|
|
|
|
|
return encodeBase64(source.c_str(), source.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<char> StringUtils::decodeBase64(const char *source, bool *ok)
|
|
|
|
|
{
|
|
|
|
|
static const int decode64_table[256] = {
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
|
|
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
|
|
|
|
|
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
|
|
|
|
49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
|
*ok = true;
|
|
|
|
|
|
|
|
|
|
std::vector<char> answer;
|
|
|
|
|
answer.reserve(strlen(source) * 3 / 4);
|
|
|
|
|
|
|
|
|
|
int mode = 0;
|
|
|
|
|
int left = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
int dec = decode64_table[(unsigned char)*source];
|
|
|
|
|
if (dec == -1) break;
|
|
|
|
|
source++;
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case 0: // we have no bits and get 6
|
|
|
|
|
left = dec;
|
|
|
|
|
mode = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // we have 6 bits and keep 4
|
|
|
|
|
answer.push_back((left<<2) | (dec>>4));
|
|
|
|
|
left = dec & 15;
|
|
|
|
|
mode = 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: // we have 4 bits and get 6, we keep 2
|
|
|
|
|
answer.push_back((left<<4) | (dec>>2));
|
|
|
|
|
left = dec & 3;
|
|
|
|
|
mode = 3;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3: // we have 2 bits and get 6
|
|
|
|
|
answer.push_back((left<<6) | dec);
|
|
|
|
|
mode = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case 0: break; // 4n base64 characters processed: ok
|
|
|
|
|
case 1: // 4n+1 base64 character processed: impossible
|
|
|
|
|
*ok = false;
|
|
|
|
|
break;
|
|
|
|
|
case 2: // 4n+2 base64 characters processed: require '=='
|
|
|
|
|
if (left || source[0] != '=' || source[1] != '=' || decode64_table[(unsigned char)source[2]] != -1)
|
|
|
|
|
*ok = false;
|
|
|
|
|
break;
|
|
|
|
|
case 3: // 4n+3 base64 characters processed: require '='
|
|
|
|
|
if (left || source[0] != '=' || decode64_table[(unsigned char)source[1]] != -1)
|
|
|
|
|
*ok = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return answer;
|
|
|
|
|
}
|