fix UIStructsmerge Platform/Common/Leaderboards

This commit is contained in:
Tropical 2026-03-22 12:13:53 -05:00
parent b9d18bf641
commit 4eda6e89fd
10 changed files with 1869 additions and 144 deletions

View file

@ -0,0 +1,97 @@
#include "../../stdafx.h"
#include "LeaderboardInterface.h"
LeaderboardInterface::LeaderboardInterface(LeaderboardManager* man) {
m_manager = man;
m_pending = false;
m_filter = (LeaderboardManager::EFilterMode)-1;
m_callback = NULL;
m_difficulty = 0;
m_type = LeaderboardManager::eStatsType_UNDEFINED;
m_startIndex = 0;
m_readCount = 0;
m_manager->OpenSession();
}
LeaderboardInterface::~LeaderboardInterface() {
m_manager->CancelOperation();
m_manager->CloseSession();
}
void LeaderboardInterface::ReadStats_Friends(
LeaderboardReadListener* callback, int difficulty,
LeaderboardManager::EStatsType type, PlayerUID myUID,
unsigned int startIndex, unsigned int readCount) {
m_filter = LeaderboardManager::eFM_Friends;
m_pending = true;
m_callback = callback;
m_difficulty = difficulty;
m_type = type;
m_myUID = myUID;
m_startIndex = startIndex;
m_readCount = readCount;
tick();
}
void LeaderboardInterface::ReadStats_MyScore(
LeaderboardReadListener* callback, int difficulty,
LeaderboardManager::EStatsType type, PlayerUID myUID,
unsigned int readCount) {
m_filter = LeaderboardManager::eFM_MyScore;
m_pending = true;
m_callback = callback;
m_difficulty = difficulty;
m_type = type;
m_myUID = myUID;
m_readCount = readCount;
tick();
}
void LeaderboardInterface::ReadStats_TopRank(
LeaderboardReadListener* callback, int difficulty,
LeaderboardManager::EStatsType type, unsigned int startIndex,
unsigned int readCount) {
m_filter = LeaderboardManager::eFM_TopRank;
m_pending = true;
m_callback = callback;
m_difficulty = difficulty;
m_type = type;
m_startIndex = startIndex;
m_readCount = readCount;
tick();
}
void LeaderboardInterface::CancelOperation() {
m_manager->CancelOperation();
m_pending = false;
}
void LeaderboardInterface::tick() {
if (m_pending) m_pending = !callManager();
}
bool LeaderboardInterface::callManager() {
switch (m_filter) {
case LeaderboardManager::eFM_Friends:
return m_manager->ReadStats_Friends(m_callback, m_difficulty,
m_type, m_myUID, m_startIndex,
m_readCount);
case LeaderboardManager::eFM_MyScore:
return m_manager->ReadStats_MyScore(m_callback, m_difficulty,
m_type, m_myUID, m_readCount);
case LeaderboardManager::eFM_TopRank:
return m_manager->ReadStats_TopRank(
m_callback, m_difficulty, m_type, m_startIndex, m_readCount);
default:
assert(false);
return true;
}
}

View file

@ -0,0 +1,40 @@
#pragma once
#include "LeaderboardManager.h"
// 4J-JEV: Simple interface for handling ReadStat failures.
class LeaderboardInterface {
private:
LeaderboardManager* m_manager;
bool m_pending;
// Arguments.
LeaderboardManager::EFilterMode m_filter;
LeaderboardReadListener* m_callback;
int m_difficulty;
LeaderboardManager::EStatsType m_type;
PlayerUID m_myUID;
unsigned int m_startIndex;
unsigned int m_readCount;
public:
LeaderboardInterface(LeaderboardManager* man);
~LeaderboardInterface();
void ReadStats_Friends(LeaderboardReadListener* callback, int difficulty,
LeaderboardManager::EStatsType type, PlayerUID myUID,
unsigned int startIndex, unsigned int readCount);
void ReadStats_MyScore(LeaderboardReadListener* callback, int difficulty,
LeaderboardManager::EStatsType type, PlayerUID myUID,
unsigned int readCount);
void ReadStats_TopRank(LeaderboardReadListener* callback, int difficulty,
LeaderboardManager::EStatsType type,
unsigned int startIndex, unsigned int readCount);
void CancelOperation();
void tick();
private:
bool callManager();
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,145 @@
#pragma once
#include "Common/Leaderboards/LeaderboardManager.h"
#ifdef __PS3__
typedef CellRtcTick SonyRtcTick;
#else
typedef SceRtcTick SonyRtcTick;
#endif
class SonyLeaderboardManager : public LeaderboardManager {
protected:
enum EStatsState {
eStatsState_Idle,
eStatsState_Getting,
eStatsState_Failed,
eStatsState_Ready,
eStatsState_Canceled,
eStatsState_Max
};
public:
SonyLeaderboardManager();
virtual ~SonyLeaderboardManager();
protected:
unsigned short m_openSessions;
C4JThread* m_threadScoreboard;
bool m_running;
int m_titleContext;
int32_t m_requestId;
// SceNpId m_myNpId;
static int scoreboardThreadEntry(LPVOID lpParam);
void scoreboardThreadInternal();
virtual bool getScoreByIds();
virtual bool getScoreByRange();
virtual bool setScore();
std::queue<RegisterScore> m_views;
CRITICAL_SECTION m_csViewsLock;
EStatsState m_eStatsState; // State of the stats read
// EFilterMode m_eFilterMode;
ReadScore* m_scores;
unsigned int m_maxRank;
// SceNpScoreRankData *m_stats;
public:
virtual void Tick();
// Open a session
virtual bool OpenSession();
// Close a session
virtual void CloseSession();
// Delete a session
virtual void DeleteSession();
// Write the given stats
// This is called synchronously and will not free any memory allocated for
// views when it is done
virtual bool WriteStats(unsigned int viewCount, ViewIn views);
virtual bool ReadStats_Friends(LeaderboardReadListener* callback,
int difficulty, EStatsType type,
PlayerUID myUID, unsigned int startIndex,
unsigned int readCount);
virtual bool ReadStats_MyScore(LeaderboardReadListener* callback,
int difficulty, EStatsType type,
PlayerUID myUID, unsigned int readCount);
virtual bool ReadStats_TopRank(LeaderboardReadListener* callback,
int difficulty, EStatsType type,
unsigned int startIndex,
unsigned int readCount);
// Perform a flush of the stats
virtual void FlushStats();
// Cancel the current operation
virtual void CancelOperation();
// Is the leaderboard manager idle.
virtual bool isIdle();
protected:
int getBoardId(int difficulty, EStatsType);
SceNpScorePlayerRankData* addPadding(unsigned int num,
SceNpScoreRankData* rankData);
void convertToOutput(unsigned int& num, ReadScore* out,
SceNpScorePlayerRankData* rankData,
SceNpScoreComment* comm);
void toBinary(void* out, SceNpScoreComment* in);
void fromBinary(SceNpScoreComment** out, void* in);
void toBase32(SceNpScoreComment* out, void* in);
void fromBase32(void* out, SceNpScoreComment* in);
void toSymbols(char*);
void fromSymbols(char*);
bool test_string(std::string);
void initReadScoreStruct(ReadScore& out, SceNpScoreRankData&);
void fillReadScoreStruct(ReadScore& out, SceNpScoreComment& comment);
static bool SortByRank(const ReadScore& lhs, const ReadScore& rhs);
protected:
// 4J-JEV: Interface differences:
// Sce NP score library function redirects.
virtual HRESULT initialiseScoreUtility() { return ERROR_SUCCESS; }
virtual bool scoreUtilityAlreadyInitialised(HRESULT hr) { return false; }
virtual HRESULT createTitleContext(const SceNpId& npId) = 0;
virtual HRESULT destroyTitleContext(int titleContext) = 0;
virtual HRESULT createTransactionContext(int titleContext) = 0;
virtual HRESULT abortTransactionContext(int transactionContext) = 0;
virtual HRESULT destroyTransactionContext(int transactionContext) = 0;
virtual HRESULT fillByIdsQuery(const SceNpId& myNpId, SceNpId*& npIds,
uint32_t& len);
#if (defined __ORBIS__) || (defined __PSVITA__)
virtual HRESULT getFriendsList(
sce::Toolkit::NP::Utilities::Future<sce::Toolkit::NP::FriendsList>&
friendsList) = 0;
#endif
virtual char* getComment(SceNpScoreComment* comment) = 0;
};

View file

@ -0,0 +1,133 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 Ren<EFBFBD> Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
Ren<EFBFBD> Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "../../stdafx.h"
#include "base64.h"
#include <iostream>
static const sstd::td::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
// 4J ADDED,
sstd::td::string base64_encode(sstd::td::string str) {
return base64_encode(reinterpret_cast<const unsigned char*>(str.c_str()),
str.length());
}
sstd::td::string base64_encode(unsigned char const* bytes_to_encode,
unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 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 (int ii = 0; (ii < 4); ii++)
ret += base64_chars[char_array_4[ii]];
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++) char_array_3[j] = '\0';
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 (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]];
while ((i++ < 3)) ret += '=';
}
return ret;
}
sstd::td::string base64_decode(sstd::td::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') &&
is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_];
in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
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];
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++) char_array_4[j] = 0;
for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
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];
}
return ret;
}

View file

@ -0,0 +1,7 @@
#pragma once
#include <string>
std::string base64_encode(std::string str);
std::string base64_encode(unsigned char const*, unsigned int len);
std::string base64_decode(std::string const& s);

View file

@ -1,7 +1,7 @@
#pragma once
#include "UIScene.h"
#include "../Leaderboards/LeaderboardManager.h"
#include "../Leaderboards/LeaderboardInterface.h"
class UIScene_LeaderboardsMenu : public UIScene,
public LeaderboardReadListener {

View file

@ -5,6 +5,7 @@
#include <cstdint>
#include "UIEnums.h"
#include "../App_Defines.h"
class Container;
class Inventory;
@ -253,54 +254,79 @@ typedef struct _JoinMenuInitData {
// More Options
typedef struct _LaunchMoreOptionsMenuInitData {
bool bOnlineGame = true;
bool bInviteOnly = false;
bool bAllowFriendsOfFriends = true;
bool bOnlineGame;
bool bInviteOnly;
bool bAllowFriendsOfFriends;
bool bGenerateOptions = false;
bool bStructures = false;
bool bFlatWorld = false;
bool bBonusChest = false;
bool bGenerateOptions;
bool bStructures;
bool bFlatWorld;
bool bBonusChest;
bool bPVP = true;
bool bTrust = false;
bool bFireSpreads = true;
bool bTNT = true;
bool bPVP;
bool bTrust;
bool bFireSpreads;
bool bTNT;
bool bHostPrivileges = false;
bool bResetNether = false;
bool bHostPrivileges;
bool bResetNether;
bool bOnlineSettingChangedBySystem = false;
bool bMobGriefing;
bool bKeepInventory;
bool bDoMobSpawning;
bool bDoMobLoot;
bool bDoTileDrops;
bool bNaturalRegeneration;
bool bDoDaylightCycle;
bool bDoMobSpawning = false;
bool bDoDaylightCycle = false;
int iPad = -1;
bool bOnlineSettingChangedBySystem;
std::uint32_t dwTexturePack = 0;
int iPad;
std::wstring seed = L"";
int worldSize = 3;
bool bDisableSaving = false;
DWORD dwTexturePack;
std::wstring seed;
int worldSize;
bool bDisableSaving;
EGameHostOptionWorldSize currentWorldSize;
EGameHostOptionWorldSize newWorldSize;
bool newWorldSizeOverwriteEdges;
_LaunchMoreOptionsMenuInitData() {
memset(this, 0, sizeof(_LaunchMoreOptionsMenuInitData));
bOnlineGame = true;
bInviteOnly = false;
bAllowFriendsOfFriends = true;
bGenerateOptions = false;
bStructures = false;
bFlatWorld = false;
bBonusChest = false;
bPVP = true;
bTrust = false;
bFireSpreads = true;
worldSize = 3;
seed = L"";
bDisableSaving = false;
newWorldSize = e_worldSize_Unknown;
newWorldSizeOverwriteEdges = false;
bTNT = false;
bHostPrivileges = false;
bResetNether = false;
bMobGriefing = true;
bKeepInventory = false;
bDoMobSpawning = false;
bDoMobLoot = true;
bDoTileDrops = true;
bNaturalRegeneration = true;
bDoDaylightCycle = true;
bOnlineSettingChangedBySystem = false;
iPad = 0;
dwTexturePack = 0;
worldSize = 3;
seed = L"";
bDisableSaving = false;
currentWorldSize = e_worldSize_Unknown;
newWorldSize = e_worldSize_Unknown;
newWorldSizeOverwriteEdges = false;
}
} LaunchMoreOptionsMenuInitData;

View file

@ -1,7 +1,13 @@
/*
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 Ren<EFBFBD> Nyffenegger
base64 encoding and decoding with C++.
More information at
https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
Version: 2.rc.09 (release candidate)
Copyright (C) 2004-2017, 2020-2022 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
@ -21,136 +27,256 @@
3. This notice may not be removed or altered from any source distribution.
Ren<EFBFBD> Nyffenegger rene.nyffenegger@adp-gmbh.ch
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "../../../../Minecraft.World/Platform/stdafx.h"
#include "base64.h"
#include <iostream>
static const std::wstring base64_chars =
L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
L"abcdefghijklmnopqrstuvwxyz"
L"0123456789+/";
#include <algorithm>
#include <stdexcept>
//
// Depending on the url parameter in base64_chars, one of
// two sets of base64 characters needs to be chosen.
// They differ in their last two characters.
//
static const char* base64_chars[2] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/",
static inline bool is_base64(wchar_t c)
{
return (isalnum(c) || (c == L'+') || (c == L'/'));
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"-_"};
static unsigned int pos_of_char(const unsigned char chr) {
//
// Return the position of chr within base64_encode()
//
if (chr >= 'A' && chr <= 'Z') return chr - 'A';
else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
else
//
// 2020-10-23: Throw std::exception rather than const char*
//(Pablo Martin-Gomez, https://github.com/Bouska)
//
throw std::runtime_error("Input is not valid base64-encoded data.");
}
// 4J changed to use Platform::String
Platform::String^ base64_encode(unsigned char* chars_to_encode, unsigned int in_len)
{
std::wstring ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
static std::string insert_linebreaks(std::string str, size_t distance) {
//
// Provided by https://github.com/JomaCorpFX, adapted by me.
//
if (!str.length()) {
return "";
}
while (in_len--)
{
char_array_3[i++] = *(chars_to_encode++);
if (i == 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;
size_t pos = distance;
for(int ii = 0; (ii <4) ; ii++)
{
ret += base64_chars[char_array_4[ii]];
}
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
{
char_array_3[j] = '\0';
}
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 (j = 0; (j < i + 1); j++)
{
ret += base64_chars[char_array_4[j]];
}
while((i++ < 3))
{
ret += L'=';
}
}
return ref new Platform::String(ret.c_str());
while (pos < str.size()) {
str.insert(pos, "\n");
pos += distance + 1;
}
return str;
}
void base64_decode(Platform::String ^encoded_string, unsigned char *output, unsigned int out_len)
{
int in_len = encoded_string->Length();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4];
unsigned char char_array_3[3];
template <typename String, unsigned int line_length>
static std::string encode_with_line_breaks(String s) {
return insert_linebreaks(base64_encode(s, false), line_length);
}
unsigned char *pucOut = output;
template <typename String>
static std::string encode_pem(String s) {
return encode_with_line_breaks<String, 64>(s);
}
while (in_len-- && ( encoded_string->Data()[in_] != L'=') && is_base64(encoded_string->Data()[in_]))
{
char_array_4[i++] = (unsigned char)(encoded_string->Data()[in_]);
in_++;
if (i ==4)
{
for (i = 0; i <4; i++)
{
char_array_4[i] = (unsigned char )base64_chars.find(char_array_4[i]);
}
template <typename String>
static std::string encode_mime(String s) {
return encode_with_line_breaks<String, 76>(s);
}
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];
template <typename String>
static std::string encode(String s, bool url) {
return base64_encode(reinterpret_cast<const unsigned char*>(s.data()), s.length(), url);
}
for (i = 0; (i < 3); i++)
{
*pucOut++ = char_array_3[i];
if( ( pucOut - output ) >= out_len ) return;
}
i = 0;
}
}
std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
if(i)
{
for (j = i; j <4; j++)
{
char_array_4[j] = 0;
}
size_t len_encoded = (in_len +2) / 3 * 4;
for (j = 0; j <4; j++)
{
char_array_4[j] = (unsigned char )base64_chars.find(char_array_4[j]);
}
unsigned char trailing_char = url ? '.' : '=';
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];
//
// Choose set of base64 characters. They differ
// for the last two positions, depending on the url
// parameter.
// A bool (as is the parameter url) is guaranteed
// to evaluate to either 0 or 1 in C++ therefore,
// the correct character set is chosen by subscripting
// base64_chars with url.
//
const char* base64_chars_ = base64_chars[url];
for (j = 0; (j < i - 1); j++)
{
*pucOut++ = char_array_3[j];
if( ( pucOut - output ) >= out_len ) return;
}
}
}
std::string ret;
ret.reserve(len_encoded);
unsigned int pos = 0;
while (pos < in_len) {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
if (pos+1 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
if (pos+2 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]);
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
ret.push_back(trailing_char);
}
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
ret.push_back(trailing_char);
ret.push_back(trailing_char);
}
pos += 3;
}
return ret;
}
template <typename String>
static std::string decode(String const& encoded_string, bool remove_linebreaks) {
//
// decode(…) is templated so that it can be used with String = const std::string&
// or std::string_view (requires at least C++17)
//
if (encoded_string.empty()) return std::string();
if (remove_linebreaks) {
std::string copy(encoded_string);
copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
return base64_decode(copy, false);
}
size_t length_of_string = encoded_string.length();
size_t pos = 0;
//
// The approximate length (bytes) of the decoded string might be one or
// two bytes smaller, depending on the amount of trailing equal signs
// in the encoded string. This approximation is needed to reserve
// enough space in the string to be returned.
//
size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
std::string ret;
ret.reserve(approx_length_of_decoded_string);
while (pos < length_of_string) {
//
// Iterate over encoded input string in chunks. The size of all
// chunks except the last one is 4 bytes.
//
// The last chunk might be padded with equal signs or dots
// in order to make it 4 bytes in size as well, but this
// is not required as per RFC 2045.
//
// All chunks except the last one produce three output bytes.
//
// The last chunk produces at least one and up to three bytes.
//
size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos+1) );
//
// Emit the first output byte that is produced in each chunk:
//
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(encoded_string.at(pos+0)) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
encoded_string.at(pos+2) != '=' &&
encoded_string.at(pos+2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
)
{
//
// Emit a chunk's second byte (which might not be produced in the last chunk).
//
unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos+2) );
ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
if ( ( pos + 3 < length_of_string ) &&
encoded_string.at(pos+3) != '=' &&
encoded_string.at(pos+3) != '.'
)
{
//
// Emit a chunk's third byte (which might not be produced in the last chunk).
//
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string.at(pos+3)) ));
}
}
pos += 4;
}
return ret;
}
std::string base64_decode(std::string const& s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
std::string base64_encode(std::string const& s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem (std::string const& s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string const& s) {
return encode_mime(s);
}
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode(std::string_view s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem(std::string_view s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string_view s) {
return encode_mime(s);
}
std::string base64_decode(std::string_view s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
#endif // __cplusplus >= 201703L

View file

@ -1,6 +1,35 @@
#pragma once
//
// base64 encoding and decoding with C++.
// Version: 2.rc.09 (release candidate)
//
#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#include <string>
Platform::String^ base64_encode(unsigned char* chars_to_encode, unsigned int in_len);
void base64_decode(Platform::String ^encoded_string, unsigned char *output, unsigned int out_len);
#if __cplusplus >= 201703L
#include <string_view>
#endif // __cplusplus >= 201703L
std::string base64_encode (std::string const& s, bool url = false);
std::string base64_encode_pem (std::string const& s);
std::string base64_encode_mime(std::string const& s);
std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
std::string base64_encode(unsigned char const*, size_t len, bool url = false);
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode (std::string_view s, bool url = false);
std::string base64_encode_pem (std::string_view s);
std::string base64_encode_mime(std::string_view s);
std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
#endif // __cplusplus >= 201703L
#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */