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 */
017package org.apache.commons.io.input;
018
019import static org.apache.commons.io.IOUtils.EOF;
020
021import java.io.IOException;
022import java.io.InputStream;
023
024/**
025 * A decorating input stream that counts the number of bytes that have passed
026 * through the stream so far.
027 * <p>
028 * A typical use case would be during debugging, to ensure that data is being
029 * read as expected.
030 * </p>
031 * @deprecated Use {@link BoundedInputStream} (unbounded by default).
032 */
033@Deprecated
034public class CountingInputStream extends ProxyInputStream {
035
036    /** The count of bytes read. */
037    private long count;
038
039    /**
040     * Constructs a new CountingInputStream.
041     *
042     * @param in  the InputStream to delegate to
043     */
044    public CountingInputStream(final InputStream in) {
045        super(in);
046    }
047
048    CountingInputStream(final InputStream in, final ProxyInputStream.AbstractBuilder<?, ?> builder) {
049        super(in, builder);
050    }
051
052    CountingInputStream(final ProxyInputStream.AbstractBuilder<?, ?> builder) throws IOException {
053        super(builder);
054    }
055
056    /**
057     * Adds the number of read bytes to the count.
058     *
059     * @param n number of bytes read, or -1 if no more bytes are available
060     * @throws IOException Not thrown here but subclasses may throw.
061     * @since 2.0
062     */
063    @Override
064    protected synchronized void afterRead(final int n) throws IOException {
065        if (n != EOF) {
066            count += n;
067        }
068        super.afterRead(n);
069    }
070
071    /**
072     * Gets number of bytes that have passed through this stream.
073     * <p>
074     * NOTE: This method is an alternative for {@code getCount()}
075     * and was added because that method returns an integer which will
076     * result in incorrect count for files over 2GB.
077     * </p>
078     *
079     * @return the number of bytes accumulated
080     * @since 1.3
081     */
082    public synchronized long getByteCount() {
083        return count;
084    }
085
086    /**
087     * Gets number of bytes that have passed through this stream.
088     * <p>
089     * This method throws an ArithmeticException if the
090     * count is greater than can be expressed by an {@code int}.
091     * See {@link #getByteCount()} for a method using a {@code long}.
092     * </p>
093     *
094     * @return the number of bytes accumulated
095     * @throws ArithmeticException if the byte count is too large
096     * @deprecated Use {@link #getByteCount()}.
097     */
098    @Deprecated
099    public int getCount() {
100        final long result = getByteCount();
101        if (result > Integer.MAX_VALUE) {
102            throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
103        }
104        return (int) result;
105    }
106
107    /**
108     * Resets the byte count back to 0.
109     * <p>
110     * NOTE: This method is an alternative for {@code resetCount()}
111     * and was added because that method returns an integer which will
112     * result in incorrect count for files over 2GB.
113     * </p>
114     *
115     * @return the count previous to resetting
116     * @since 1.3
117     */
118    public synchronized long resetByteCount() {
119        final long tmp = count;
120        count = 0;
121        return tmp;
122    }
123
124    /**
125     * Resets the byte count back to 0.
126     * <p>
127     * This method throws an ArithmeticException if the
128     * count is greater than can be expressed by an {@code int}.
129     * See {@link #resetByteCount()} for a method using a {@code long}.
130     * </p>
131     *
132     * @return the count previous to resetting
133     * @throws ArithmeticException if the byte count is too large
134     * @deprecated Use {@link #resetByteCount()}.
135     */
136    @Deprecated
137    public int resetCount() {
138        final long result = resetByteCount();
139        if (result > Integer.MAX_VALUE) {
140            throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
141        }
142        return (int) result;
143    }
144
145    /**
146     * Skips the stream over the specified number of bytes, adding the skipped
147     * amount to the count.
148     *
149     * @param length  the number of bytes to skip
150     * @return the actual number of bytes skipped
151     * @throws IOException if an I/O error occurs.
152     * @see java.io.InputStream#skip(long)
153     */
154    @Override
155    public synchronized long skip(final long length) throws IOException {
156        final long skip = super.skip(length);
157        count += skip;
158        return skip;
159    }
160
161}