private static void encode3Bytes(byte[] source, int sourceOff, int numBytes,
                                       byte[] target, int targetOff) {
    //We have to shift left 24 all the bytes in order to throw away the 1's
    //that appear when Java considers a value as negative (it happens when
    //the value is cast from byte to int).
    //Then we shift rigth 8, 16 and 24 the 3 bytes to do an OR operation, in
    //order to have the 3 bytes as only one number, and to be able to
    //exctract the 4 bytes of 6 bits later.
    //Example: imagine that the bytes are 'a'(97), 'b'(98), and 'c'(99)
    //     'a'(97)   00000000 00000000 00000000 01100001
    //     'b'(98)   00000000 00000000 00000000 01100010
    //     'c'(99)   00000000 00000000 00000000 01100011
    //Now, shifting left 24 all of them, we would have:
    //     'a'(97)   01100001 00000000 00000000 00000000
    //     'b'(98)   01100010 00000000 00000000 00000000
    //     'c'(99)   01100011 00000000 00000000 00000000
    //Now, shifting rigth 8, 16, and 24 respectively, we would have:
    //     'a'(97)   00000000 01100001 00000000 00000000   (>>>8)
    //     'b'(98)   00000000 00000000 01100010 00000000   (>>>16)
    //     'c'(99)   00000000 00000000 00000000 01100011   (>>>24)
    //Applying the OR operation, we would have
    //     result =  00000000 01100001 01100010 01100011
    //which is the number that contains the 3 bytes one behind the other
    int result =   ( numBytes > 0 ? ((source[sourceOff] << 24) >>>  8) : 0)
                 | ( numBytes > 1 ? ((source[sourceOff + 1] << 24) >>> 16) : 0)
                 | ( numBytes > 2 ? ((source[sourceOff + 2] << 24) >>> 24) : 0);

    //It is determined if the target array needs padding characters, according
    //to the number of bytes taken from the source array. If it is 1 byte, then
    //it needs 2 "="; if they are 2 bytes, then it needs 1 "="; and if they are
    //3, then there is no need of padding characters. Then the 4 bytes are written
    //to the target array.
    //Following the example above, the first byte to be written to the target array
    //would be obtained by shifting right 18 the number obtained above:
    //     result    00000000 01100001 01100010 01100011
    //     >>> 18    00000000 00000000 00000000 0001100001 01100010 01100011
    //which means that we are taking only the first 6 bits of the original number
    //The second byte would be obtained by shifting right 12 and doing the
    //AND operation against 0x3f, just to leave the last 6 bits
    //     result    00000000 01100001 01100010 01100011
    //     >>> 12    00000000 00000000 00000110 000101100010 01100011
    //     0x3f      00000000 00000000 00000000 00111111
    //which means that we are taking the last 6 bits of the resulting number
    //the last 2 bytes to be written to the encoded array are obtained in a
    //similar way to the one described here. They are obtained by shifting
    //right 6 and 0; and by doing the AND operation against 0x3f.
    switch(numBytes){
      //it does not need padding characters.
      case 3:
        target[targetOff]     = TABLE64[(result >>> 18)];
        target[targetOff + 1] = TABLE64[(result >>> 12) & 0x3f];
        target[targetOff + 2] = TABLE64[(result >>> 6) & 0x3f];
        target[targetOff + 3] = TABLE64[(result) & 0x3f];
        break;

      //it needs 1 padding character
      case 2:
        target[targetOff]     = TABLE64[(result >>> 18)];
        target[targetOff + 1] = TABLE64[(result >>> 12) & 0x3f];
        target[targetOff + 2] = TABLE64[(result >>> 6) & 0x3f];
        target[targetOff + 3 ] = EQUALS_CHAR;
        break;

      //it needs 2 padding characters
      case 1:
        target[targetOff]     = TABLE64[(result >>> 18)];
        target[targetOff + 1] = TABLE64[(result >>> 12) & 0x3f];
        target[targetOff + 2] = EQUALS_CHAR;
        target[targetOff + 3] = EQUALS_CHAR;
        break;

    }//switch

  }//encode3Bytes