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