/** * Decodes the specified character sequence, and returns the resulting {@code byte[]}. * This is the inverse operation to {@link #encode(byte[])}. * * @throws DecodingException if the input is not a valid encoded string according to this * encoding. */ final byte[] decodeChecked(CharSequence chars) throws DecodingException { chars = padding().trimTrailingFrom(chars); ByteInput decodedInput = decodingStream(asCharInput(chars)); byte[] tmp = new byte[maxDecodedSize(chars.length())]; int index = 0; try { for (int i = decodedInput.read(); i != -1; i = decodedInput.read()) { tmp[index++] = (byte) i; } } catch (DecodingException badInput) { throw badInput; } catch (IOException impossible) { throw new AssertionError(impossible); } return extract(tmp, index); }
/** * Decodes the specified character sequence, and returns the resulting {@code byte[]}. * This is the inverse operation to {@link #encode(byte[])}. * * @throws IllegalArgumentException if the input is not a valid encoded string according to this * encoding. */ public final byte[] decode(CharSequence chars) { chars = padding().trimTrailingFrom(chars); ByteInput decodedInput = decodingStream(asCharInput(chars)); byte[] tmp = new byte[maxDecodedSize(chars.length())]; int index = 0; try { for (int i = decodedInput.read(); i != -1; i = decodedInput.read()) { tmp[index++] = (byte) i; } } catch (IOException badInput) { throw new IllegalArgumentException(badInput); } return extract(tmp, index); }
@Override ByteInput decodingStream(final CharInput reader) { checkNotNull(reader); return new ByteInput() { int bitBuffer = 0; int bitBufferLength = 0; int readChars = 0; boolean hitPadding = false; final CharMatcher paddingMatcher = padding(); @Override public int read() throws IOException { while (true) { int readChar = reader.read(); if (readChar == -1) { if (!hitPadding && !alphabet.isValidPaddingStartPosition(readChars)) { throw new DecodingException("Invalid input length " + readChars); } return -1; } readChars++; char ch = (char) readChar; if (paddingMatcher.matches(ch)) { if (!hitPadding && (readChars == 1 || !alphabet.isValidPaddingStartPosition(readChars - 1))) { throw new DecodingException("Padding cannot start at index " + readChars); } hitPadding = true; } else if (hitPadding) { throw new DecodingException( "Expected padding character but found '" + ch + "' at index " + readChars); } else { bitBuffer <<= alphabet.bitsPerChar; bitBuffer |= alphabet.decode(ch); bitBufferLength += alphabet.bitsPerChar; if (bitBufferLength >= 8) { bitBufferLength -= 8; return (bitBuffer >> bitBufferLength) & 0xFF; } } } } @Override public void close() throws IOException { reader.close(); } }; }
@Override ByteInput decodingStream(final CharInput input) { return delegate.decodingStream(ignoringInput(input, separatorChars)); }
@Override ByteInput decodingStream(final CharInput reader) { checkNotNull(reader); return new ByteInput() { int bitBuffer = 0; int bitBufferLength = 0; int readChars = 0; boolean hitPadding = false; final CharMatcher paddingMatcher = padding(); @Override public int read() throws IOException { while (true) { int readChar = reader.read(); if (readChar == -1) { if (!hitPadding && !alphabet.isValidPaddingStartPosition(readChars)) { throw new IOException("Invalid input length " + readChars); } return -1; } readChars++; char ch = (char) readChar; if (paddingMatcher.matches(ch)) { if (!hitPadding && (readChars == 1 || !alphabet.isValidPaddingStartPosition(readChars - 1))) { throw new IOException("Padding cannot start at index " + readChars); } hitPadding = true; } else if (hitPadding) { throw new IOException( "Expected padding character but found '" + ch + "' at index " + readChars); } else { bitBuffer <<= alphabet.bitsPerChar; bitBuffer |= alphabet.decode(ch); bitBufferLength += alphabet.bitsPerChar; if (bitBufferLength >= 8) { bitBufferLength -= 8; return (bitBuffer >> bitBufferLength) & 0xFF; } } } } @Override public void close() throws IOException { reader.close(); } }; }
abstract ByteInput decodingStream(CharInput charInput);