/* * Universal Media Server, for streaming any media to DLNA * compatible renderers based on the http://www.ps3mediaserver.org. * Copyright (C) 2012 UMS developers. * * This program is a free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License only. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.pms.util; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; /** * This class can be used as a "drop in replacement" for * {@link BufferedInputStream} if you want to alter the buffering behavior. * This will fake the behavior of a {@link BufferedInputStream} with its own * "mark position" while keeping the real mark at 0. This means that the start * position won't be invalidated just because a mark is placed later than at * position 0. {@code marklimit} in {@link #mark(int)} is ignored and the value * given in the constructor is used instead, meaning that this can be passed to * other methods without the danger of them invalidating the start position by * specifying a too small {@code marklimit}.<br> * <br> * This also offers two additional methods {@link #isFullResetAvailable()} and * {@link #fullReset()}. A full reset will ignore any marks set and reset the * read position to the start.<br> * <br> * The intended use for this class is to use an {@link InputStream} instance * for multiple purposes without having to read the whole stream into memory, * for example when parsing information early in the stream with multiple * parsers. * * @author Nadahar */ public class ResettableInputStream extends BufferedInputStream { protected int overriddenMarkpos = 0; /** * Creates a {@link ResettableInputStream} and saves its argument, the * input stream {@code in}, for later use. An internal buffer array is * created and stored in {@code buf}. * * @param in the underlying input stream. * @param marklimit the maximum size to buffer before the mark/start point * gets invalidated. This overrides the parameter sent * when calling {@link #mark(int)}. */ public ResettableInputStream(InputStream in, int marklimit) { super(in); this.marklimit = marklimit; markpos = 0; } /** * Creates a {@link ResettableInputStream} with the specified buffer * size, and saves its argument, the input stream {@code in}, for later * use. An internal buffer array of length {@code size} is created and * stored in {@code buf}. * * @param in the underlying input stream. * @param size the initial buffer size. * @param marklimit the maximum size to buffer before the mark/start point * gets invalidated. This overrides the parameter sent * when calling {@link #mark(int)}. * @exception IllegalArgumentException if {@code size} <= 0. */ public ResettableInputStream(InputStream in, int size, int marklimit) { super(in, size); this.marklimit = marklimit; markpos = 0; } /** * See the general contract of {@link InputStream#mark(int)}. * * @param readlimit - ignored. * @see ResettableInputStream#reset() */ @Override public synchronized void mark(int readlimit) { //Ignore readlimit, we adhere to the constructor limit overriddenMarkpos = pos; } /** * See the general contract of {@link InputStream#reset()}. * <p> * If {@code markpos} is {@code -1} (the start position has been * invalidated), an {@link IOException} is thrown. Otherwise, {@code pos} * is set equal to {@code markpos}. * * @exception IOException if the mark has been invalidated, or the stream * has been closed by invoking its {@link #close()} * method, or an I/O error occurs. * @see ResettableInputStream#mark(int) */ @Override public synchronized void reset() throws IOException { super.reset(); if (overriddenMarkpos < 0) { overriddenMarkpos = 0; } pos = overriddenMarkpos; } /** * @return Whether a call to {@link #fullReset()} will succeed. */ public synchronized boolean isFullResetAvailable() { return markpos == 0; } /** * Resets the stream read position to the start if possible. * * @throws IOException if the full reset fails. */ public synchronized void fullReset() throws IOException { super.reset(); pos = 0; } }