void decodeImpl(final char[] chars, final int offset, final int length, Base64Context ctx)
      throws FileParsingException {
    try {

      if (ctx.eof) {
        return;
      }
      byte[] buffer = null;
      if (length < 0) {
        ctx.eof = true;
      } else {
        // in general the resulting decoded array should be 3/4 the
        // length of the input. We double that amount, as consequent scans
        // might have longer base64 strings
        buffer = ctx.ensureBufferHasCapacityLeft(length * 2);
      }

      int readPos = offset;
      byte b;
      for (int i = 0; i < length; i++) {
        // I don't know why in Apache impl this has been checked on every iteration
        //final byte[] buffer = ensureBufferSize(decodeSize, context);
        b = (byte) chars[readPos++];
        if (b == PAD) {
          // We're done.
          ctx.eof = true;
          break;
        } else {
          try {
            if (b >= 0 && b < DECODE_TABLE.length) {
              final int result = DECODE_TABLE[b];
              if (result >= 0) {
                ctx.modulus = (ctx.modulus + 1) % BYTES_PER_ENCODED_BLOCK;
                ctx.ibitWorkArea = (ctx.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
                if (ctx.modulus == 0) {
                  buffer[ctx.pos] = (byte) ((ctx.ibitWorkArea >> 16) & MASK_8BITS);
                  ctx.pos++;
                  buffer[ctx.pos] = (byte) ((ctx.ibitWorkArea >> 8) & MASK_8BITS);
                  ctx.pos++;
                  buffer[ctx.pos] = (byte) (ctx.ibitWorkArea & MASK_8BITS);
                  ctx.pos++;
                }
              }
            }
          } catch (ArrayIndexOutOfBoundsException e) {
            throw new FileParsingException(
                "Something went wrong in Base64 decoder, got out of array bounds", e);
          }
        }
      }

      // Two forms of EOF as far as base64 decoder is concerned: actual
      // EOF (-1) and first time '=' character is encountered in stream.
      // This approach makes the '=' padding characters completely optional.
      if (ctx.eof && ctx.modulus != 0) {
        buffer = ctx.ensureBufferHasCapacityLeft(decodeSize);

        // We have some spare bits remaining
        // Output all whole multiples of 8 bits and ignore the rest
        switch (ctx.modulus) {
          //case 0 : // impossible, as excluded above
          case 1: // 6 bits - ignore entirely
            // TODO not currently tested; perhaps it is impossible?
            break;
          case 2: // 12 bits = 8 + 4
            ctx.ibitWorkArea = ctx.ibitWorkArea >> 4; // dump the extra 4 bits
            buffer[ctx.pos++] = (byte) ((ctx.ibitWorkArea) & MASK_8BITS);
            break;
          case 3: // 18 bits = 8 + 8 + 2
            ctx.ibitWorkArea = ctx.ibitWorkArea >> 2; // dump 2 bits
            buffer[ctx.pos++] = (byte) ((ctx.ibitWorkArea >> 8) & MASK_8BITS);
            buffer[ctx.pos++] = (byte) ((ctx.ibitWorkArea) & MASK_8BITS);
            break;
          default:
            throw new IllegalStateException("Impossible modulus " + ctx.modulus);
        }
      }

    } finally {
      ctx.syncBufferPos();
    }
  }
void decodeImpl ( final char [ ] chars , final int offset , final int length , Base64Context ctx ) throws FileParsingException { try { if ( ctx . eof ) { return ; } byte [ ] buffer = null ; if ( length < 0 ) { ctx . eof = true ; } else { buffer = ctx . ensureBufferHasCapacityLeft ( length * 2 ) ; } int readPos = offset ; byte b ; for ( int i = 0 ; i < length ; i ++ ) { b = ( byte ) chars [ readPos ++ ] ; if ( b == PAD ) { ctx . eof = true ; break ; } else { try { if ( b >= 0 && b < DECODE_TABLE . length ) { final int result = DECODE_TABLE [ b ] ; if ( result >= 0 ) { ctx . modulus = ( ctx . modulus + 1 ) % BYTES_PER_ENCODED_BLOCK ; ctx . ibitWorkArea = ( ctx . ibitWorkArea << BITS_PER_ENCODED_BYTE ) + result ; if ( ctx . modulus == 0 ) { buffer [ ctx . pos ] = ( byte ) ( ( ctx . ibitWorkArea > > 16 ) & MASK_8BITS ) ; ctx . pos ++ ; buffer [ ctx . pos ] = ( byte ) ( ( ctx . ibitWorkArea > > 8 ) & MASK_8BITS ) ; ctx . pos ++ ; buffer [ ctx . pos ] = ( byte ) ( ctx . ibitWorkArea & MASK_8BITS ) ; ctx . pos ++ ; } } } } catch ( ArrayIndexOutOfBoundsException e ) { throw new FileParsingException ( "Something went wrong in Base64 decoder, got out of array bounds" , e ) ; } } } if ( ctx . eof && ctx . modulus != 0 ) { buffer = ctx . ensureBufferHasCapacityLeft ( decodeSize ) ; switch ( ctx . modulus ) { case 1 : break ; case 2 : ctx . ibitWorkArea = ctx . ibitWorkArea > > 4 ; buffer [ ctx . pos ++ ] = ( byte ) ( ( ctx . ibitWorkArea ) & MASK_8BITS ) ; break ; case 3 : ctx . ibitWorkArea = ctx . ibitWorkArea > > 2 ; buffer [ ctx . pos ++ ] = ( byte ) ( ( ctx . ibitWorkArea > > 8 ) & MASK_8BITS ) ; buffer [ ctx . pos ++ ] = ( byte ) ( ( ctx . ibitWorkArea ) & MASK_8BITS ) ; break ; default : throw new IllegalStateException ( "Impossible modulus " + ctx . modulus ) ; } } } finally { ctx . syncBufferPos ( ) ; } }
<p>
Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at
least twice: once with the data to decode, and once with inAvail set to "-1" to alert decoder
that EOF has been reached. The "-1" call is not necessary when decoding, but it doesn't hurt,
either.
</p>
<p>
Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled,
since CR and LF are silently ignored, but has implications for other bytes, too. This method
subscribes to the garbage-in, garbage-out philosophy: it will not check the provided data for
validity.
</p>
<p>
Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
</p>

@param chars char[] array of ascii data to base64 decode.
@param offset offset in the input array where the data starts
@param length length of the data, starting at offset in the input array
@param ctx the context to be used