You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
249 lines
8.2 KiB
C++
249 lines
8.2 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "HttpPrivatePCH.h"
|
|
#include "Base64.h"
|
|
|
|
|
|
/** The table used to encode a 6 bit value as an ascii character */
|
|
uint8 FBase64::EncodingAlphabet[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', '+', '/' };
|
|
|
|
/** The table used to convert an ascii character into a 6 bit value */
|
|
uint8 FBase64::DecodingAlphabet[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D,
|
|
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
|
|
0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
|
|
0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
|
|
|
/**
|
|
* Encodes a binary uint8 array into a Base64 string
|
|
*
|
|
* @param Source the binary data to convert
|
|
*
|
|
* @return a string that encodes the binary data in a way that can be safely transmitted via various Internet protocols
|
|
*/
|
|
FString FBase64::Encode(const TArray<uint8>& Source)
|
|
{
|
|
return Encode((uint8*)Source.GetTypedData(), Source.Num());
|
|
}
|
|
|
|
/**
|
|
* Decodes a Base64 string into an array of bytes
|
|
*
|
|
* @param Source the stringified data to convert
|
|
* @param Dest the out buffer that will be filled with the decoded data
|
|
*
|
|
* @return true if the buffer was decoded, false if it failed to decode
|
|
*/
|
|
bool FBase64::Decode(const FString& Source, TArray<uint8>& Dest)
|
|
{
|
|
uint32 Length = Source.Len();
|
|
// Size must be a multiple of 4
|
|
if (Length % 4)
|
|
{
|
|
return false;
|
|
}
|
|
// Each 4 uint8 chunk of characters is 3 bytes of data
|
|
uint32 ExpectedLength = Length / 4 * 3;
|
|
// Add the number we need for output
|
|
Dest.AddZeroed(ExpectedLength);
|
|
uint8* Buffer = Dest.GetTypedData();
|
|
uint32 PadCount = 0;
|
|
bool bWasSuccessful = Decode(TCHAR_TO_ANSI(*Source), Length, Dest.GetTypedData(), PadCount);
|
|
if (bWasSuccessful)
|
|
{
|
|
if (PadCount > 0)
|
|
{
|
|
Dest.RemoveAt(ExpectedLength - PadCount, PadCount);
|
|
}
|
|
}
|
|
return bWasSuccessful;
|
|
}
|
|
|
|
/**
|
|
* Encodes a FString into a Base64 string
|
|
*
|
|
* @param Source the string data to convert
|
|
*
|
|
* @return a string that encodes the binary data in a way that can be safely transmitted via various Internet protocols
|
|
*/
|
|
FString FBase64::Encode(const FString& Source)
|
|
{
|
|
return Encode((uint8*)TCHAR_TO_ANSI(*Source), Source.Len());
|
|
}
|
|
|
|
/**
|
|
* Decodes a Base64 string into a FString
|
|
*
|
|
* @param Source the stringified data to convert
|
|
* @param Dest the out buffer that will be filled with the decoded data
|
|
*/
|
|
bool FBase64::Decode(const FString& Source, FString& Dest)
|
|
{
|
|
uint32 Length = Source.Len();
|
|
// Size must be a multiple of 4
|
|
if (Length % 4)
|
|
{
|
|
return false;
|
|
}
|
|
// Each 4 uint8 chunk of characters is 3 bytes of data
|
|
uint32 ExpectedLength = Length / 4 * 3;
|
|
TArray<ANSICHAR> TempDest;
|
|
TempDest.AddZeroed(ExpectedLength);
|
|
uint8* Buffer = (uint8*)TempDest.GetTypedData();
|
|
uint32 PadCount = 0;
|
|
|
|
bool bWasSuccessful = Decode(TCHAR_TO_ANSI(*Source), Length, Buffer, PadCount);
|
|
if (bWasSuccessful)
|
|
{
|
|
if (PadCount > 0)
|
|
{
|
|
Buffer[ExpectedLength - PadCount] = 0;
|
|
}
|
|
else
|
|
{
|
|
TempDest.Add('\0');
|
|
}
|
|
Dest = ANSI_TO_TCHAR(TempDest.GetTypedData());
|
|
}
|
|
return bWasSuccessful;
|
|
}
|
|
|
|
/**
|
|
* Encodes the source into a Base64 string
|
|
*
|
|
* @param Source the binary payload to stringify
|
|
* @param Length the length of the payload that needs encoding
|
|
*
|
|
* @return the stringified form of the binary data
|
|
*/
|
|
FString FBase64::Encode(uint8* Source, uint32 Length)
|
|
{
|
|
// Each 3 uint8 set of data expands to 4 bytes and must be padded to 4 bytes
|
|
uint32 ExpectedLength = (Length + 2) / 3 * 4;
|
|
FString OutBuffer;
|
|
OutBuffer.Empty(ExpectedLength);
|
|
|
|
ANSICHAR EncodedBytes[5];
|
|
// Null terminate this so we can append it easily as a string
|
|
EncodedBytes[4] = 0;
|
|
// Loop through the buffer converting 3 bytes of binary data at a time
|
|
while (Length >= 3)
|
|
{
|
|
uint8 A = *Source++;
|
|
uint8 B = *Source++;
|
|
uint8 C = *Source++;
|
|
Length -= 3;
|
|
// The algorithm takes 24 bits of data (3 bytes) and breaks it into 4 6bit chunks represented as ascii
|
|
uint32 ByteTriplet = A << 16 | B << 8 | C;
|
|
// Use the 6bit block to find the representation ascii character for it
|
|
EncodedBytes[3] = EncodingAlphabet[ByteTriplet & 0x3F];
|
|
// Shift each time to get the next 6 bit chunk
|
|
ByteTriplet >>= 6;
|
|
EncodedBytes[2] = EncodingAlphabet[ByteTriplet & 0x3F];
|
|
ByteTriplet >>= 6;
|
|
EncodedBytes[1] = EncodingAlphabet[ByteTriplet & 0x3F];
|
|
ByteTriplet >>= 6;
|
|
EncodedBytes[0] = EncodingAlphabet[ByteTriplet & 0x3F];
|
|
// Now we can append this buffer to our destination string
|
|
OutBuffer += EncodedBytes;
|
|
}
|
|
// Since this algorithm operates on blocks, we may need to pad the last chunks
|
|
if (Length > 0)
|
|
{
|
|
uint8 A = *Source++;
|
|
uint8 B = 0;
|
|
uint8 C = 0;
|
|
// Grab the second character if it is a 2 uint8 finish
|
|
if (Length == 2)
|
|
{
|
|
B = *Source;
|
|
}
|
|
uint32 ByteTriplet = A << 16 | B << 8 | C;
|
|
// Pad with = to make a 4 uint8 chunk
|
|
EncodedBytes[3] = '=';
|
|
ByteTriplet >>= 6;
|
|
// If there's only one 1 uint8 left in the source, then you need 2 pad chars
|
|
if (Length == 1)
|
|
{
|
|
EncodedBytes[2] = '=';
|
|
}
|
|
else
|
|
{
|
|
EncodedBytes[2] = EncodingAlphabet[ByteTriplet & 0x3F];
|
|
}
|
|
// Now encode the remaining bits the same way
|
|
ByteTriplet >>= 6;
|
|
EncodedBytes[1] = EncodingAlphabet[ByteTriplet & 0x3F];
|
|
ByteTriplet >>= 6;
|
|
EncodedBytes[0] = EncodingAlphabet[ByteTriplet & 0x3F];
|
|
OutBuffer += EncodedBytes;
|
|
}
|
|
return OutBuffer;
|
|
}
|
|
|
|
/**
|
|
* Decodes a Base64 string into an array of bytes
|
|
*
|
|
* @param Source the stringified data to convert
|
|
* @param Length the length of the buffer being converted
|
|
* @param Dest the out buffer that will be filled with the decoded data
|
|
* @param PadCount the out count of the padding on the orignal buffer (0 to 2)
|
|
*
|
|
* @return true if the buffer was decoded, false if it failed to decode
|
|
*/
|
|
bool FBase64::Decode(const ANSICHAR* Source, uint32 Length, uint8* Dest, uint32& PadCount)
|
|
{
|
|
PadCount = 0;
|
|
uint8 DecodedValues[4];
|
|
while (Length)
|
|
{
|
|
// Decode the next 4 BYTEs
|
|
for (int32 Index = 0; Index < 4; Index++)
|
|
{
|
|
// Tell the caller if there were any pad bytes
|
|
if (*Source == '=')
|
|
{
|
|
PadCount++;
|
|
}
|
|
DecodedValues[Index] = DecodingAlphabet[(int32)(*Source++)];
|
|
// Abort on values that we don't understand
|
|
if (DecodedValues[Index] == -1)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
Length -= 4;
|
|
// Rebuild the original 3 bytes from the 4 chunks of 6 bits
|
|
uint32 OriginalTriplet = DecodedValues[0];
|
|
OriginalTriplet <<= 6;
|
|
OriginalTriplet |= DecodedValues[1];
|
|
OriginalTriplet <<= 6;
|
|
OriginalTriplet |= DecodedValues[2];
|
|
OriginalTriplet <<= 6;
|
|
OriginalTriplet |= DecodedValues[3];
|
|
// Now we can tear the uint32 into bytes
|
|
Dest[2] = OriginalTriplet & 0xFF;
|
|
OriginalTriplet >>= 8;
|
|
Dest[1] = OriginalTriplet & 0xFF;
|
|
OriginalTriplet >>= 8;
|
|
Dest[0] = OriginalTriplet & 0xFF;
|
|
Dest += 3;
|
|
}
|
|
return true;
|
|
}
|