001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.io;
016
017import static com.google.common.base.Preconditions.checkNotNull;
018import static java.util.Objects.requireNonNull;
019
020import com.google.common.annotations.GwtIncompatible;
021import com.google.common.annotations.J2ktIncompatible;
022import java.io.FilterInputStream;
023import java.io.IOException;
024import java.io.InputStream;
025
026/**
027 * An {@link InputStream} that counts the number of bytes read.
028 *
029 * @author Chris Nokleberg
030 * @since 1.0
031 */
032@J2ktIncompatible
033@GwtIncompatible
034public final class CountingInputStream extends FilterInputStream {
035
036  private long count;
037  private long mark = -1;
038
039  /**
040   * Wraps another input stream, counting the number of bytes read.
041   *
042   * @param in the input stream to be wrapped
043   */
044  public CountingInputStream(InputStream in) {
045    super(checkNotNull(in));
046  }
047
048  private InputStream in() {
049    return requireNonNull(in); // guaranteed safe by the constructor
050  }
051
052  /** Returns the number of bytes read. */
053  public long getCount() {
054    return count;
055  }
056
057  @Override
058  public int read() throws IOException {
059    int result = in().read();
060    if (result != -1) {
061      count++;
062    }
063    return result;
064  }
065
066  @Override
067  public int read(byte[] b, int off, int len) throws IOException {
068    int result = in().read(b, off, len);
069    if (result != -1) {
070      count += result;
071    }
072    return result;
073  }
074
075  @Override
076  public long skip(long n) throws IOException {
077    long result = in().skip(n);
078    count += result;
079    return result;
080  }
081
082  @Override
083  public synchronized void mark(int readlimit) {
084    in().mark(readlimit);
085    mark = count;
086    // it's okay to mark even if mark isn't supported, as reset won't work
087  }
088
089  @Override
090  public synchronized void reset() throws IOException {
091    if (!in().markSupported()) {
092      throw new IOException("Mark not supported");
093    }
094    if (mark == -1) {
095      throw new IOException("Mark not set");
096    }
097
098    in().reset();
099    count = mark;
100  }
101}