public static class Convert
{
public static String ToBase64String(byte[] inArray)
{
if (inArray == null)
{
throw new ArgumentNullException("inArray");
}
Contract.Ensures(Contract.Result<string>() != null);
Contract.EndContractBlock();
return ToBase64String(inArray, 0, inArray.Length, Base64FormattingOptions.None);
}
[System.Runtime.InteropServices.ComVisible(false)]
public static String ToBase64String(byte[] inArray, Base64FormattingOptions options)
{
if (inArray == null)
{
throw new ArgumentNullException("inArray");
}
Contract.Ensures(Contract.Result<string>() != null);
Contract.EndContractBlock();
return ToBase64String(inArray, 0, inArray.Length, options);
}
public static String ToBase64String(byte[] inArray, int offset, int length)
{
return ToBase64String(inArray, offset, length, Base64FormattingOptions.None);
}
[System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(false)]
public static unsafe String ToBase64String(byte[] inArray, int offset, int length, Base64FormattingOptions options)
{
//Do data verfication
if (inArray == null)
throw new ArgumentNullException("inArray");
if (length < 0)
throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
if (options < Base64FormattingOptions.None || options > Base64FormattingOptions.InsertLineBreaks)
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options));
Contract.Ensures(Contract.Result<string>() != null);
Contract.EndContractBlock();
int inArrayLength;
int stringLength;
inArrayLength = inArray.Length;
if (offset > (inArrayLength - length))
throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_OffsetLength"));
if (inArrayLength == 0)
return String.Empty;
bool insertLineBreaks = (options == Base64FormattingOptions.InsertLineBreaks);
//Create the new string. This is the maximally required length.
stringLength = ToBase64_CalculateAndValidateOutputLength(length, insertLineBreaks);
string returnString = string.FastAllocateString(stringLength);
fixed (char* outChars = returnString)
{
fixed (byte* inData = inArray)
{
int j = ConvertToBase64Array(outChars, inData, offset, length, insertLineBreaks);
BCLDebug.Assert(returnString.Length == j, "returnString.Length == j");
return returnString;
}
}
}
public static int ToBase64CharArray(byte[] inArray, int offsetIn, int length, char[] outArray, int offsetOut)
{
Contract.Ensures(Contract.Result<int>() >= 0);
Contract.Ensures(Contract.Result<int>() <= outArray.Length);
Contract.EndContractBlock();
return ToBase64CharArray(inArray, offsetIn, length, outArray, offsetOut, Base64FormattingOptions.None);
}
[System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(false)]
public static unsafe int ToBase64CharArray(byte[] inArray, int offsetIn, int length, char[] outArray, int offsetOut, Base64FormattingOptions options)
{
//Do data verfication
if (inArray == null)
throw new ArgumentNullException("inArray");
if (outArray == null)
throw new ArgumentNullException("outArray");
if (length < 0)
throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
if (offsetIn < 0)
throw new ArgumentOutOfRangeException("offsetIn", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
if (offsetOut < 0)
throw new ArgumentOutOfRangeException("offsetOut", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
if (options < Base64FormattingOptions.None || options > Base64FormattingOptions.InsertLineBreaks)
{
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options));
}
Contract.Ensures(Contract.Result<int>() >= 0);
Contract.Ensures(Contract.Result<int>() <= outArray.Length);
Contract.EndContractBlock();
int retVal;
int inArrayLength;
int outArrayLength;
int numElementsToCopy;
inArrayLength = inArray.Length;
if (offsetIn > (int)(inArrayLength - length))
throw new ArgumentOutOfRangeException("offsetIn", Environment.GetResourceString("ArgumentOutOfRange_OffsetLength"));
if (inArrayLength == 0)
return 0;
bool insertLineBreaks = (options == Base64FormattingOptions.InsertLineBreaks);
//This is the maximally required length that must be available in the char array
outArrayLength = outArray.Length;
// Length of the char buffer required
numElementsToCopy = ToBase64_CalculateAndValidateOutputLength(length, insertLineBreaks);
if (offsetOut > (int)(outArrayLength - numElementsToCopy))
throw new ArgumentOutOfRangeException("offsetOut", Environment.GetResourceString("ArgumentOutOfRange_OffsetOut"));
fixed (char* outChars = &outArray[offsetOut])
{
fixed (byte* inData = inArray)
{
retVal = ConvertToBase64Array(outChars, inData, offsetIn, length, insertLineBreaks);
}
}
return retVal;
}
[System.Security.SecurityCritical] // auto-generated
private static unsafe int ConvertToBase64Array(char* outChars, byte* inData, int offset, int length, bool insertLineBreaks)
{
int lengthmod3 = length % 3;
int calcLength = offset + (length - lengthmod3);
int j = 0;
int charcount = 0;
//Convert three bytes at a time to base64 notation. This will consume 4 chars.
int i;
// get a pointer to the base64Table to avoid unnecessary range checking
fixed (char* base64 = base64Table)
{
for (i = offset; i < calcLength; i += 3)
{
if (insertLineBreaks)
{
if (charcount == base64LineBreakPosition)
{
outChars[j++] = '\r';
outChars[j++] = '\n';
charcount = 0;
}
charcount += 4;
}
outChars[j] = base64[(inData[i] & 0xfc) >> 2];
outChars[j + 1] = base64[((inData[i] & 0x03) << 4) | ((inData[i + 1] & 0xf0) >> 4)];
outChars[j + 2] = base64[((inData[i + 1] & 0x0f) << 2) | ((inData[i + 2] & 0xc0) >> 6)];
outChars[j + 3] = base64[(inData[i + 2] & 0x3f)];
j += 4;
}
//Where we left off before
i = calcLength;
if (insertLineBreaks && (lengthmod3 != 0) && (charcount == base64LineBreakPosition))
{
outChars[j++] = '\r';
outChars[j++] = '\n';
}
switch (lengthmod3)
{
case 2: //One character padding needed
outChars[j] = base64[(inData[i] & 0xfc) >> 2];
outChars[j + 1] = base64[((inData[i] & 0x03) << 4) | ((inData[i + 1] & 0xf0) >> 4)];
outChars[j + 2] = base64[(inData[i + 1] & 0x0f) << 2];
outChars[j + 3] = base64[64]; //Pad
j += 4;
break;
case 1: // Two character padding needed
outChars[j] = base64[(inData[i] & 0xfc) >> 2];
outChars[j + 1] = base64[(inData[i] & 0x03) << 4];
outChars[j + 2] = base64[64]; //Pad
outChars[j + 3] = base64[64]; //Pad
j += 4;
break;
}
}
return j;
}
private static int ToBase64_CalculateAndValidateOutputLength(int inputLength, bool insertLineBreaks)
{
long outlen = ((long)inputLength) / 3 * 4; // the base length - we want integer division here.
outlen += ((inputLength % 3) != 0) ? 4 : 0; // at most 4 more chars for the remainder
if (outlen == 0)
return 0;
if (insertLineBreaks)
{
long newLines = outlen / base64LineBreakPosition;
if ((outlen % base64LineBreakPosition) == 0)
{
--newLines;
}
outlen += newLines * 2; // the number of line break chars we'll add, "\r\n"
}
if (outlen > int.MaxValue)
throw new OutOfMemoryException();
return (int)outlen;
}
[SecuritySafeCritical]
public static Byte[] FromBase64String(String s)
{
if (s == null)
throw new ArgumentNullException("s");
Contract.EndContractBlock();
unsafe
{
fixed (Char* sPtr = s)
{
return FromBase64CharPtr(sPtr, s.Length);
}
}
}
[SecuritySafeCritical]
public static Byte[] FromBase64CharArray(Char[] inArray, Int32 offset, Int32 length)
{
if (inArray == null)
throw new ArgumentNullException("inArray");
#if FEATURE_LEGACYNETCF
Contract.EndContractBlock();
// throw FormatException, to ensure compatibility with Mango Apps.
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
if(inArray.Length == 0) {
throw new FormatException();
}
}
#endif
if (length < 0)
throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
if (offset > inArray.Length - length)
throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_OffsetLength"));
#if !FEATURE_LEGACYNETCF // Our compat hack above breaks CCRewrite's rules on valid contracts.
Contract.EndContractBlock();
#endif
unsafe
{
fixed (Char* inArrayPtr = inArray)
{
return FromBase64CharPtr(inArrayPtr + offset, length);
}
}
}
[SecurityCritical]
private static unsafe Byte[] FromBase64CharPtr(Char* inputPtr, Int32 inputLength)
{
Contract.Assert(0 <= inputLength);
while (inputLength > 0)
{
Int32 lastChar = inputPtr[inputLength - 1];
if (lastChar != (Int32)' ' && lastChar != (Int32)'\n' && lastChar != (Int32)'\r' && lastChar != (Int32)'\t')
break;
inputLength--;
}
// Compute the output length:
Int32 resultLength = FromBase64_ComputeResultLength(inputPtr, inputLength);
Contract.Assert(0 <= resultLength);
Byte[] decodedBytes = new Byte[resultLength];
// Convert Base64 chars into bytes:
Int32 actualResultLength;
fixed (Byte* decodedBytesPtr = decodedBytes)
actualResultLength = FromBase64_Decode(inputPtr, inputLength, decodedBytesPtr, resultLength);
return decodedBytes;
}
}