public int ReadBase64 (byte [] buffer, int offset, int length)
{
if (offset < 0)
throw CreateArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
else if (length < 0)
throw CreateArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
else if (buffer.Length < offset + length)
throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
if (reader.IsEmptyElement)
return 0;
if (length == 0) // It does not raise an error.
return 0;
int bufIndex = offset;
int bufLast = offset + length;
if (base64CacheStartsAt >= 0) {
for (int i = base64CacheStartsAt; i < 3; i++) {
buffer [bufIndex++] = base64Cache [base64CacheStartsAt++];
if (bufIndex == bufLast)
return bufLast - offset;
}
}
for (int i = 0; i < 3; i++)
base64Cache [i] = 0;
base64CacheStartsAt = -1;
int max = (int) System.Math.Ceiling (4.0 / 3 * length);
int additional = max % 4;
if (additional > 0)
max += 4 - additional;
char [] chars = new char [max];
int charsLength = getter != null ?
getter (chars, 0, max) :
ReadValueChunk (chars, 0, max);
byte b = 0;
byte work = 0;
for (int i = 0; i < charsLength - 3; i++) {
if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
break;
b = (byte) (GetBase64Byte (chars [i]) << 2);
if (bufIndex < bufLast)
buffer [bufIndex] = b;
else {
if (base64CacheStartsAt < 0)
base64CacheStartsAt = 0;
base64Cache [0] = b;
}
// charsLength mod 4 might not equals to 0.
if (++i == charsLength)
break;
if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
break;
b = GetBase64Byte (chars [i]);
work = (byte) (b >> 4);
if (bufIndex < bufLast) {
buffer [bufIndex] += work;
bufIndex++;
}
else
base64Cache [0] += work;
work = (byte) ((b & 0xf) << 4);
if (bufIndex < bufLast) {
buffer [bufIndex] = work;
}
else {
if (base64CacheStartsAt < 0)
base64CacheStartsAt = 1;
base64Cache [1] = work;
}
if (++i == charsLength)
break;
if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
break;
b = GetBase64Byte (chars [i]);
work = (byte) (b >> 2);
if (bufIndex < bufLast) {
buffer [bufIndex] += work;
bufIndex++;
}
else
base64Cache [1] += work;
work = (byte) ((b & 3) << 6);
if (bufIndex < bufLast)
buffer [bufIndex] = work;
else {
if (base64CacheStartsAt < 0)
base64CacheStartsAt = 2;
base64Cache [2] = work;
}
if (++i == charsLength)
break;
if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
break;
work = GetBase64Byte (chars [i]);
if (bufIndex < bufLast) {
buffer [bufIndex] += work;
bufIndex++;
}
else
base64Cache [2] += work;
}
int ret = System.Math.Min (bufLast - offset, bufIndex - offset);
if (ret < length && charsLength > 0)
return ret + ReadBase64 (buffer, offset + ret, length - ret);
else
return ret;
}