code: public int read() throws IOException {
      // Read the next non-whitespace character
      int x;
      do {
        x = in.read();
        if (x == -1) {
          return -1;
        }
      } while (Character.isWhitespace((char) x));
      charCount++;
  
      // The '=' sign is just padding
      if (x == '=') {
        return -1; // effective end of stream
      }
  
      // Convert from raw form to 6-bit form
      x = ints[x];
  
      // Calculate which character we're decoding now
      int mode = (charCount - 1) % 4;
  
      // First char save all six bits, go for another
      if (mode == 0) {
        carryOver = x & 63;
        return read();
      }
      // Second char use previous six bits and first two new bits,
      // save last four bits
      else if (mode == 1) {
        int decoded = ((carryOver << 2) + (x >> 4)) & 255;
        carryOver = x & 15;
        return decoded;
      }
      // Third char use previous four bits and first four new bits,
      // save last two bits
      else if (mode == 2) {
        int decoded = ((carryOver << 4) + (x >> 2)) & 255;
        carryOver = x & 3;
        return decoded;
      }
      // Fourth char use previous two bits and all six new bits
      else if (mode == 3) {
        int decoded = ((carryOver << 6) + x) & 255;
        return decoded;
      }
      return -1; // can't actually reach this line
    }
docs: *
  Returns the next decoded character from the stream, or -1 if end of stream was reached.
  
  @return the decoded character, or -1 if the end of the input stream is reached
  @exception IOException if an I/O error occurs