All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jmrtd.io.SplittableInputStream Maven / Gradle / Ivy

There is a newer version: 0.7.42
Show newest version
/*
 * JMRTD - A Java API for accessing machine readable travel documents.
 *
 * Copyright (C) 2006 - 2014  The JMRTD team
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * $Id: SplittableInputStream.java 1573 2015-03-04 16:00:18Z martijno $
 */

package org.jmrtd.io;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Logger;

/**
 * An input stream which will wrap another input stream (and yield the same bytes) and which can
 * spawn new fresh input stream copies (using {@link #getInputStream(int)})
 * (that also yield the same bytes).
 * 
 * @author Martijn Oostdijk ([email protected])
 * 
 * @version $Revision: 1573 $
 */
public class SplittableInputStream extends InputStream {

	private static final Logger LOGGER = Logger.getLogger("org.jmrtd");
	
	public InputStreamBuffer inputStreamBuffer; // FIXME should be private
	private InputStreamBuffer.SubInputStream carrier;

	/**
	 * Wraps an input stream so that copy streams can be split off.
	 * 
	 * @param inputStream the original input stream
	 * @param length the precise length of bytes that the original input stream provides
	 */
	public SplittableInputStream(InputStream inputStream, int length) {
		this.inputStreamBuffer = new InputStreamBuffer(inputStream, length);
		this.carrier = inputStreamBuffer.getInputStream();
	}

	public void updateFrom(SplittableInputStream other) {
		inputStreamBuffer.updateFrom(other.inputStreamBuffer);
	}
	
	/**
	 * Gets a copy of the inputstream positioned at position.
	 * 
	 * @param position a position between 0 and {@link #getPosition()}
	 * @return a fresh input stream
	 */
	public InputStream getInputStream(int position) {
		try {
			InputStream inputStream = inputStreamBuffer.getInputStream();
			long skippedBytes = 0L;
			while (skippedBytes < position) {
				skippedBytes += inputStream.skip(position - skippedBytes);
			}
			return inputStream;
		} catch (IOException ioe) {
			LOGGER.severe("Exception: " + ioe.getMessage());
			throw new IllegalStateException(ioe.getMessage());
		}
	}

	/**
	 * The position of the input stream (the number of bytes read since this input stream was constructed)
	 * 
	 * @return the position of this input stream
	 */
	public int getPosition() {
		return carrier.getPosition();
	}

	/**
	 * Reads the next byte of data from the input stream. The value byte is
	 * returned as an int in the range 0 to
	 * 255. If no byte is available because the end of the stream
	 * has been reached, the value -1 is returned. This method
	 * blocks until input data is available, the end of the stream is detected,
	 * or an exception is thrown.
	 *
	 * @return     the next byte of data, or -1 if the end of the
	 *             stream is reached.
	 * @exception  IOException  if an I/O error occurs.
	 */
	public int read() throws IOException {
		return carrier.read();
	}

	/**
	 * Skips over and discards n bytes of data from this input
	 * stream. The skip method may, for a variety of reasons, end
	 * up skipping over some smaller number of bytes, possibly 0.
	 * This may result from any of a number of conditions; reaching end of file
	 * before n bytes have been skipped is only one possibility.
	 * The actual number of bytes skipped is returned.  If n is
	 * negative, no bytes are skipped.
	 *
	 * @param n the number of bytes to be skipped.
	 * @return the actual number of bytes skipped.
	 * @throws IOException if the stream does not support seek, or if some other I/O error occurs.
	 */
	public long skip(long n) throws IOException {
		return carrier.skip(n);
	}

	/**
	 * Returns an estimate of the number of bytes that can be read (or
	 * skipped over) from this input stream without blocking by the next
	 * invocation of a method for this input stream. The next invocation
	 * might be the same thread or another thread.  A single read or skip of this
	 * many bytes will not block, but may read or skip fewer bytes.
	 *
	 * @return an estimate of the number of bytes that can be read (or skipped
	 *         over) from this input stream without blocking or {@code 0} when
	 *         it reaches the end of the input stream.
	 * @throws IOException on error
	 */
	public int available() throws IOException {
		return carrier.available();
	}

	/**
	 * Closes this input stream and releases any system resources associated
	 * with the stream.
	 *
	 * @throws IOException on error
	 */
	public void close() throws IOException {
		carrier.close();
	}

	/**
	 * Marks the current position in this input stream. A subsequent call to
	 * the reset method repositions this stream at the last marked
	 * position so that subsequent reads re-read the same bytes.
	 *
	 * 

The readlimit arguments tells this input stream to * allow that many bytes to be read before the mark position gets * invalidated.

* *

The general contract of mark is that, if the method * markSupported returns true, the stream somehow * remembers all the bytes read after the call to mark and * stands ready to supply those same bytes again if and whenever the method * reset is called. However, the stream is not required to * remember any data at all if more than readlimit bytes are * read from the stream before reset is called.

* * @param readlimit the maximum limit of bytes that can be read before the mark position becomes invalid. * * @see java.io.InputStream#reset() */ public synchronized void mark(int readlimit) { carrier.mark(readlimit); } /** * Repositions this stream to the position at the time the * mark method was last called on this input stream. * * The general contract of reset is: * *
    * *
  • If the method markSupported returns * true, then: * *
    • If the method mark has not been called since * the stream was created, or the number of bytes read from the stream * since mark was last called is larger than the argument * to mark at that last call, then an * IOException might be thrown. * *
    • If such an IOException is not thrown, then the * stream is reset to a state such that all the bytes read since the * most recent call to mark (or since the start of the * file, if mark has not been called) will be resupplied * to subsequent callers of the read method, followed by * any bytes that otherwise would have been the next input data as of * the time of the call to reset.
    * *
  • If the method markSupported returns * false, then: * *
    • The call to reset may throw an * IOException. * *
    • If an IOException is not thrown, then the stream * is reset to a fixed state that depends on the particular type of the * input stream and how it was created. The bytes that will be supplied * to subsequent callers of the read method depend on the * particular type of the input stream.
* * @exception IOException if this stream has not been marked or if the mark has been invalidated. * * @see java.io.InputStream#mark(int) * @see java.io.IOException * * @throws IOException on error */ public synchronized void reset() throws IOException { carrier.reset(); } /** * Tests if this input stream supports the mark and * reset methods. Whether or not mark and * reset are supported is an invariant property of a * particular input stream instance. The markSupported method * of InputStream returns false. * * @return true if this stream instance supports the mark * and reset methods; false otherwise. * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ public boolean markSupported() { return carrier.markSupported(); } public int getLength() { return inputStreamBuffer.getLength(); } public int getBytesBuffered() { return inputStreamBuffer.getBytesBuffered(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy