Java tutorial
/* * Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package com.baidubce.util; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.http.annotation.NotThreadSafe; import com.baidubce.BceClientException; /** * Used to perform length check to ensure the number of bytes read from the underlying input stream is the same as the * expected total. */ @NotThreadSafe public class LengthCheckInputStream extends FilterInputStream { public static final boolean INCLUDE_SKIPPED_BYTES = true; public static final boolean EXCLUDE_SKIPPED_BYTES = false; /** * Total number of bytes expected to be read from the underlying input stream. */ private final long expectedLength; /** * True if skipped bytes are to be included as part of the data length; false otherwise. */ private final boolean includeSkipped; /** * The length of the data read from the underlying input stream so far. */ private long dataLength; private long marked; // used for mark-and-reset purposes /** * Constructs an input stream that performs length check to ensure the number of bytes read from the underlying * input stream is the same as the expected total. * * @param in the underlying input stream * @param expectedLength the total length of the data in bytes expected to be read from the underlying input stream; * must be non-negative. * @param includeSkipped true if bytes skipped are to be considered as part of the data length; false otherwise. * Typically, this parameter should be set to false for uploading data to BCE, * but set to true for receiving data from BCE. */ public LengthCheckInputStream(InputStream in, long expectedLength, boolean includeSkipped) { super(in); if (expectedLength < 0) { throw new IllegalArgumentException(); } this.expectedLength = expectedLength; this.includeSkipped = includeSkipped; } /** * {@inheritDoc} * * @throws com.baidubce.BceClientException if the data length read has exceeded the expected total, or if the total * data length is not the same as the expected total. */ @Override public int read() throws IOException { final int c = super.read(); if (c >= 0) { this.dataLength++; } this.checkLength(c == -1); return c; } /** * {@inheritDoc} * * @throws com.baidubce.BceClientException if the data length read has exceeded the expected total, or if the total * data length is not the same as the expected total. */ @Override public int read(byte[] b, int off, int len) throws IOException { int readLen = super.read(b, off, len); this.dataLength += readLen >= 0 ? readLen : 0; this.checkLength(readLen == -1); return readLen; } @Override public void mark(int readlimit) { super.mark(readlimit); this.marked = this.dataLength; } @Override public void reset() throws IOException { super.reset(); if (super.markSupported()) { this.dataLength = this.marked; } } /** * Checks the data length read so far against the expected total. * * @param eof true if end of stream has been encountered; false otherwise * @throws com.baidubce.BceClientException if the data length read has exceeded the expected total, or if the total * data length is not the same as the expected total. */ private void checkLength(boolean eof) { if (eof) { if (this.dataLength != this.expectedLength) { throw new BceClientException("Data read (" + this.dataLength + ") has a different length than the expected (" + this.expectedLength + ")"); } } else if (this.dataLength > this.expectedLength) { throw new BceClientException( "More data read (" + this.dataLength + ") than expected (" + this.expectedLength + ")"); } } /** * {@inheritDoc} * * @throws com.baidubce.BceClientException if {@link #includeSkipped} is true and the data length skipped has * exceeded the expected total. */ @Override public long skip(long n) throws IOException { final long skipped = super.skip(n); if (this.includeSkipped && skipped > 0) { this.dataLength += skipped; this.checkLength(false); } return skipped; } }