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 that have passed. */
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    /**
049     * Adds the number of read bytes to the count.
050     *
051     * @param n number of bytes read, or -1 if no more bytes are available
052     * @throws IOException Not thrown here but subclasses may throw.
053     * @since 2.0
054     */
055    @Override
056    protected synchronized void afterRead(final int n) throws IOException {
057        if (n != EOF) {
058            count += n;
059        }
060    }
061
062    /**
063     * Gets number of bytes that have passed through this stream.
064     * <p>
065     * NOTE: This method is an alternative for {@code getCount()}
066     * and was added because that method returns an integer which will
067     * result in incorrect count for files over 2GB.
068     * </p>
069     *
070     * @return the number of bytes accumulated
071     * @since 1.3
072     */
073    public synchronized long getByteCount() {
074        return count;
075    }
076
077    /**
078     * Gets number of bytes that have passed through this stream.
079     * <p>
080     * This method throws an ArithmeticException if the
081     * count is greater than can be expressed by an {@code int}.
082     * See {@link #getByteCount()} for a method using a {@code long}.
083     * </p>
084     *
085     * @return the number of bytes accumulated
086     * @throws ArithmeticException if the byte count is too large
087     * @deprecated Use {@link #getByteCount()}.
088     */
089    @Deprecated
090    public int getCount() {
091        final long result = getByteCount();
092        if (result > Integer.MAX_VALUE) {
093            throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
094        }
095        return (int) result;
096    }
097
098    /**
099     * Resets the byte count back to 0.
100     * <p>
101     * NOTE: This method is an alternative for {@code resetCount()}
102     * and was added because that method returns an integer which will
103     * result in incorrect count for files over 2GB.
104     * </p>
105     *
106     * @return the count previous to resetting
107     * @since 1.3
108     */
109    public synchronized long resetByteCount() {
110        final long tmp = count;
111        count = 0;
112        return tmp;
113    }
114
115    /**
116     * Resets the byte count back to 0.
117     * <p>
118     * This method throws an ArithmeticException if the
119     * count is greater than can be expressed by an {@code int}.
120     * See {@link #resetByteCount()} for a method using a {@code long}.
121     * </p>
122     *
123     * @return the count previous to resetting
124     * @throws ArithmeticException if the byte count is too large
125     * @deprecated Use {@link #resetByteCount()}.
126     */
127    @Deprecated
128    public int resetCount() {
129        final long result = resetByteCount();
130        if (result > Integer.MAX_VALUE) {
131            throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
132        }
133        return (int) result;
134    }
135
136    /**
137     * Skips the stream over the specified number of bytes, adding the skipped
138     * amount to the count.
139     *
140     * @param length  the number of bytes to skip
141     * @return the actual number of bytes skipped
142     * @throws IOException if an I/O error occurs.
143     * @see java.io.InputStream#skip(long)
144     */
145    @Override
146    public synchronized long skip(final long length) throws IOException {
147        final long skip = super.skip(length);
148        count += skip;
149        return skip;
150    }
151
152}