/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.kernel.io; import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil; import com.liferay.portal.kernel.util.StringPool; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetEncoder; /** * @author Tina Tian */ public class ReaderInputStream extends InputStream { public ReaderInputStream(Reader reader) { this( reader, StringPool.UTF8, _DEFAULT_INTPUT_BUFFER_SIZE, _DEFAULT_OUTPUT_BUFFER_SIZE); } public ReaderInputStream(Reader reader, String charsetName) { this( reader, charsetName, _DEFAULT_INTPUT_BUFFER_SIZE, _DEFAULT_OUTPUT_BUFFER_SIZE); } public ReaderInputStream( Reader reader, String charsetName, int inputBufferSize, int outputBufferSize) { _reader = reader; _charsetName = charsetName; if (inputBufferSize <= 0) { throw new IllegalArgumentException( "Input buffer size " + inputBufferSize + " must be a positive number"); } _inputBuffer = CharBuffer.allocate(inputBufferSize); _charsetEncoder = CharsetEncoderUtil.getCharsetEncoder(charsetName); _maxBytesPerChar = (int)Math.ceil(_charsetEncoder.maxBytesPerChar()); if (outputBufferSize < _maxBytesPerChar) { throw new IllegalArgumentException( "Output buffer size " + outputBufferSize + " is less than " + _maxBytesPerChar); } _outputBuffer = ByteBuffer.allocate(outputBufferSize); _outputBuffer.flip(); } @Override public int available() { return _outputBuffer.remaining() + _inputBuffer.position(); } @Override public void close() throws IOException { if (_inputBuffer != null) { _inputBuffer.clear(); _inputBuffer = null; } if (_outputBuffer != null) { _outputBuffer.clear(); _outputBuffer = null; } _reader.close(); } public String getEncoding() { return _charsetName; } @Override public int read() throws IOException { byte[] bytes = new byte[1]; int result = read(bytes, 0, 1); if (result == 1) { return bytes[0]; } else { return -1; } } @Override public int read(byte[] bytes) throws IOException { return read(bytes, 0, bytes.length); } @Override public int read(byte[] bytes, int offset, int length) throws IOException { if (bytes == null) { throw new NullPointerException(); } else if ((offset < 0) || (length < 0) || (length > (bytes.length - offset))) { throw new IndexOutOfBoundsException(); } else if (length == 0) { return 0; } int originalLength = length; while (length > 0) { int blockSize = Math.min(_outputBuffer.remaining(), length); if (blockSize > 0) { _outputBuffer.get(bytes, offset, blockSize); length -= blockSize; offset += blockSize; if (length == 0) { break; } } int inputPosition = _inputBuffer.position(); int result = _reader.read( _inputBuffer.array(), inputPosition, _inputBuffer.remaining()); if (result != -1) { _inputBuffer.position(inputPosition + result); } _inputBuffer.flip(); int inputRemaining = _inputBuffer.remaining(); if (inputRemaining <= 0) { break; } if ((inputRemaining * _maxBytesPerChar) < length) { ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, offset, length); _charsetEncoder.encode(_inputBuffer, byteBuffer, true); int outputRemaining = byteBuffer.remaining(); offset += length - outputRemaining; length = outputRemaining; } else { _outputBuffer.clear(); _charsetEncoder.encode(_inputBuffer, _outputBuffer, true); _outputBuffer.flip(); } _inputBuffer.compact(); } int result = originalLength - length; if (result == 0) { return -1; } return result; } @Override public long skip(long length) throws IOException { if (length < 0) { throw new IllegalArgumentException(); } long originalLength = length; while (length > 0) { int blockSize = (int)Math.min(_outputBuffer.remaining(), length); if (blockSize > 0) { _outputBuffer.position(_outputBuffer.position() + blockSize); length -= blockSize; if (length == 0) { break; } } int inputPosition = _inputBuffer.position(); int result = _reader.read( _inputBuffer.array(), inputPosition, _inputBuffer.remaining()); if (result != -1) { _inputBuffer.position(inputPosition + result); } _inputBuffer.flip(); if (_inputBuffer.remaining() <= 0) { break; } _outputBuffer.clear(); _charsetEncoder.encode(_inputBuffer, _outputBuffer, true); _outputBuffer.flip(); _inputBuffer.compact(); } return originalLength - length; } private static final int _DEFAULT_INTPUT_BUFFER_SIZE = 128; private static final int _DEFAULT_OUTPUT_BUFFER_SIZE = 1024; private final CharsetEncoder _charsetEncoder; private final String _charsetName; private CharBuffer _inputBuffer; private final int _maxBytesPerChar; private ByteBuffer _outputBuffer; private final Reader _reader; }