blob: b9291ef374d5480d14ccec94db70adae400490a4 [file] [log] [blame]
/*
* Copyright (c) 2020 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.net4j.util.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* An input stream for reading a {@link Reader}.
*
* @author Eike Stepper
* @since 3.13
*/
public class ReaderInputStream extends InputStream
{
private static final int MASK = 0xFF;
private final Charset charset;
private Reader reader;
private CharBuffer chars = CharBuffer.allocate(IOUtil.DEFAULT_BUFFER_SIZE);
private ByteBuffer bytes;
public ReaderInputStream(Reader reader, String encoding) throws IOException
{
this.reader = reader;
charset = encoding == null ? StandardCharsets.UTF_8 : Charset.forName(encoding);
}
public ReaderInputStream(Reader reader) throws IOException
{
this(reader, null);
}
@Override
public int available() throws IOException
{
checkClosed();
ensureBytes();
if (bytes == null)
{
return 0;
}
return bytes.remaining();
}
@Override
public int read(byte[] b, int off, int len) throws IOException
{
checkClosed();
if (len == 0)
{
return 0;
}
ensureBytes();
if (bytes == null)
{
return IOUtil.EOF;
}
int count = 0;
do
{
ensureBytes();
if (bytes == null)
{
// No more to read.
break;
}
int toRead = Math.min(bytes.remaining(), len - count);
bytes.get(b, off + count, toRead);
count = count + toRead;
} while (count < len);
return count;
}
@Override
public int read() throws IOException
{
checkClosed();
ensureBytes();
if (bytes == null)
{
return IOUtil.EOF;
}
return bytes.get() & MASK;
}
@Override
public void close() throws IOException
{
if (reader != null)
{
reader.close();
reader = null;
bytes = null;
chars = null;
}
}
private void ensureBytes() throws IOException
{
if (bytes == null || !bytes.hasRemaining())
{
checkClosed();
Buffer buffer = chars;
buffer.rewind();
int count = reader.read(chars);
if (count > 0)
{
buffer.flip();
bytes = charset.encode(chars);
}
else
{
bytes = null;
}
}
}
private void checkClosed() throws IOException
{
if (reader == null)
{
throw new IOException("Reader is closed"); //$NON-NLS-1$
}
}
}