+ if (offset < 0)
+ throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
+ else if (length < 0)
+ throw new ArgumentOutOfRangeException ("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 (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 = ReadChars (chars, 0, max);
+
+ byte b = 0;
+ byte work = 0;
+ bool loop = true;
+ 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;
+ }
+ return System.Math.Min (bufLast - offset, bufIndex - offset);