001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.io.input; 019 020import java.io.FilterInputStream; 021import java.io.IOException; 022import java.io.InputStream; 023 024import org.apache.commons.io.build.AbstractStreamBuilder; 025 026/** 027 * An unsynchronized version of {@link FilterInputStream}, not thread-safe. 028 * <p> 029 * Wraps an existing {@link InputStream} and performs some transformation on the input data while it is being read. Transformations can be anything from a 030 * simple byte-wise filtering input data to an on-the-fly compression or decompression of the underlying stream. Input streams that wrap another input stream 031 * and provide some additional functionality on top of it usually inherit from this class. 032 * </p> 033 * <p> 034 * To build an instance, use {@link Builder}. 035 * </p> 036 * <p> 037 * Provenance: Apache Harmony and modified. 038 * </p> 039 * 040 * @see Builder 041 * @see FilterInputStream 042 * @since 2.12.0 043 */ 044//@NotThreadSafe 045public class UnsynchronizedFilterInputStream extends InputStream { 046 047 // @formatter:off 048 /** 049 * Builds a new {@link UnsynchronizedFilterInputStream}. 050 * 051 * <p> 052 * Using File IO: 053 * </p> 054 * <pre>{@code 055 * UnsynchronizedFilterInputStream s = UnsynchronizedFilterInputStream.builder() 056 * .setFile(file) 057 * .get();} 058 * </pre> 059 * <p> 060 * Using NIO Path: 061 * </p> 062 * <pre>{@code 063 * UnsynchronizedFilterInputStream s = UnsynchronizedFilterInputStream.builder() 064 * .setPath(path) 065 * .get();} 066 * </pre> 067 * 068 * @see #get() 069 */ 070 // @formatter:on 071 public static class Builder extends AbstractStreamBuilder<UnsynchronizedFilterInputStream, Builder> { 072 073 /** 074 * Builds a new {@link UnsynchronizedFilterInputStream}. 075 * <p> 076 * You must set input that supports {@link #getInputStream()}, otherwise, this method throws an exception. 077 * </p> 078 * <p> 079 * This builder use the following aspects: 080 * </p> 081 * <ul> 082 * <li>{@link #getInputStream()}</li> 083 * </ul> 084 * 085 * @return a new instance. 086 * @throws IllegalStateException if the {@code origin} is {@code null}. 087 * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}. 088 * @throws IOException if an I/O error occurs. 089 * @see #getInputStream() 090 */ 091 @SuppressWarnings("resource") // Caller closes. 092 @Override 093 public UnsynchronizedFilterInputStream get() throws IOException { 094 return new UnsynchronizedFilterInputStream(getInputStream()); 095 } 096 097 } 098 099 /** 100 * Constructs a new {@link Builder}. 101 * 102 * @return a new {@link Builder}. 103 */ 104 public static Builder builder() { 105 return new Builder(); 106 } 107 108 /** 109 * The source input stream that is filtered. 110 */ 111 protected volatile InputStream inputStream; 112 113 /** 114 * Constructs a new {@code FilterInputStream} with the specified input stream as source. 115 * 116 * @param inputStream the non-null InputStream to filter reads on. 117 */ 118 UnsynchronizedFilterInputStream(final InputStream inputStream) { 119 this.inputStream = inputStream; 120 } 121 122 /** 123 * Returns the number of bytes that are available before this stream will block. 124 * 125 * @return the number of bytes available before blocking. 126 * @throws IOException if an error occurs in this stream. 127 */ 128 @Override 129 public int available() throws IOException { 130 return inputStream.available(); 131 } 132 133 /** 134 * Closes this stream. This implementation closes the filtered stream. 135 * 136 * @throws IOException if an error occurs while closing this stream. 137 */ 138 @Override 139 public void close() throws IOException { 140 inputStream.close(); 141 } 142 143 /** 144 * Sets a mark position in this stream. The parameter {@code readLimit} indicates how many bytes can be read before the mark is invalidated. Sending 145 * {@code reset()} will reposition this stream back to the marked position, provided that {@code readLimit} has not been surpassed. 146 * <p> 147 * This implementation sets a mark in the filtered stream. 148 * 149 * @param readLimit the number of bytes that can be read from this stream before the mark is invalidated. 150 * @see #markSupported() 151 * @see #reset() 152 */ 153 @SuppressWarnings("sync-override") // by design. 154 @Override 155 public void mark(final int readLimit) { 156 inputStream.mark(readLimit); 157 } 158 159 /** 160 * Indicates whether this stream supports {@code mark()} and {@code reset()}. This implementation returns whether or not the filtered stream supports 161 * marking. 162 * 163 * @return {@code true} if {@code mark()} and {@code reset()} are supported, {@code false} otherwise. 164 * @see #mark(int) 165 * @see #reset() 166 * @see #skip(long) 167 */ 168 @Override 169 public boolean markSupported() { 170 return inputStream.markSupported(); 171 } 172 173 /** 174 * Reads a single byte from the filtered stream and returns it as an integer in the range from 0 to 255. Returns -1 if the end of this stream has been 175 * reached. 176 * 177 * @return the byte read or -1 if the end of the filtered stream has been reached. 178 * @throws IOException if the stream is closed or another IOException occurs. 179 */ 180 @Override 181 public int read() throws IOException { 182 return inputStream.read(); 183 } 184 185 /** 186 * Reads bytes from this stream and stores them in the byte array {@code buffer}. Returns the number of bytes actually read or -1 if no bytes were read and 187 * the end of this stream was encountered. This implementation reads bytes from the filtered stream. 188 * 189 * @param buffer the byte array in which to store the read bytes. 190 * @return the number of bytes actually read or -1 if the end of the filtered stream has been reached while reading. 191 * @throws IOException if this stream is closed or another IOException occurs. 192 */ 193 @Override 194 public int read(final byte[] buffer) throws IOException { 195 return read(buffer, 0, buffer.length); 196 } 197 198 /** 199 * Reads at most {@code count} bytes from this stream and stores them in the byte array {@code buffer} starting at {@code offset}. Returns the number of 200 * bytes actually read or -1 if no bytes have been read and the end of this stream has been reached. This implementation reads bytes from the filtered 201 * stream. 202 * 203 * @param buffer the byte array in which to store the bytes read. 204 * @param offset the initial position in {@code buffer} to store the bytes read from this stream. 205 * @param count the maximum number of bytes to store in {@code buffer}. 206 * @return the number of bytes actually read or -1 if the end of the filtered stream has been reached while reading. 207 * @throws IOException if this stream is closed or another I/O error occurs. 208 */ 209 @Override 210 public int read(final byte[] buffer, final int offset, final int count) throws IOException { 211 return inputStream.read(buffer, offset, count); 212 } 213 214 /** 215 * Resets this stream to the last marked location. This implementation resets the target stream. 216 * 217 * @throws IOException if this stream is already closed, no mark has been set or the mark is no longer valid because more than {@code readLimit} bytes have 218 * been read since setting the mark. 219 * @see #mark(int) 220 * @see #markSupported() 221 */ 222 @SuppressWarnings("sync-override") // by design. 223 @Override 224 public void reset() throws IOException { 225 inputStream.reset(); 226 } 227 228 /** 229 * Skips {@code count} number of bytes in this stream. Subsequent {@code read()}'s will not return these bytes unless {@code reset()} is used. This 230 * implementation skips {@code count} number of bytes in the filtered stream. 231 * 232 * @param count the number of bytes to skip. 233 * @return the number of bytes actually skipped. 234 * @throws IOException if this stream is closed or another IOException occurs. 235 * @see #mark(int) 236 * @see #reset() 237 */ 238 @Override 239 public long skip(final long count) throws IOException { 240 return inputStream.skip(count); 241 } 242}