com.amazonaws.services.s3.internal.crypto.AdjustedRangeInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aws-java-sdk Show documentation
Show all versions of aws-java-sdk Show documentation
The Amazon Web Services SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).
The newest version!
/*
* Copyright 2010-2014 Amazon.com, Inc. or its affiliates. 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.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.amazonaws.services.s3.internal.crypto;
import java.io.IOException;
import java.io.InputStream;
/**
* Reads only a specific range of bytes from the underlying input stream.
*/
public class AdjustedRangeInputStream extends InputStream {
private InputStream decryptedContents;
private long virtualAvailable;
private boolean closed;
/**
* Creates a new DecryptedContentsInputStream object.
*
* @param objectContents
* The input stream containing the object contents retrieved from S3
* @param rangeBeginning
* The position of the left-most byte desired by the user
* @param rangeEnd
* The position of the right-most byte desired by the user
* @throws IOException
* If there are errors skipping to the left-most byte desired by the user.
*/
public AdjustedRangeInputStream(InputStream objectContents, long rangeBeginning, long rangeEnd) throws IOException {
this.decryptedContents = objectContents;
this.closed = false;
initializeForRead(rangeBeginning, rangeEnd);
}
/**
* Skip to the start location of the range of bytes desired by the user.
*/
private void initializeForRead(long rangeBeginning, long rangeEnd) throws IOException {
// To get to the left-most byte desired by a user, we must skip over the 16 bytes of the
// preliminary cipher block, and then possibly skip a few more bytes into the next block
// to where the the left-most byte is located.
int numBytesToSkip;
if(rangeBeginning < JceEncryptionConstants.SYMMETRIC_CIPHER_BLOCK_SIZE) {
numBytesToSkip = (int)rangeBeginning;
} else {
int offsetIntoBlock = (int)(rangeBeginning % JceEncryptionConstants.SYMMETRIC_CIPHER_BLOCK_SIZE);
numBytesToSkip = JceEncryptionConstants.SYMMETRIC_CIPHER_BLOCK_SIZE + offsetIntoBlock;
}
if(numBytesToSkip != 0) {
// Skip to the left-most desired byte. The read() method is used instead of the skip() method
// since the skip() method will not block if the underlying input stream is waiting for more input.
while(numBytesToSkip > 0) {
this.decryptedContents.read();
numBytesToSkip--;
}
}
// The number of bytes the user may read is equal to the number of the bytes in the range.
// Note that the range includes the endpoints.
this.virtualAvailable = (rangeEnd - rangeBeginning) + 1;
}
/* (non-Javadoc)
* @see java.io.InputStream#read()
*/
@Override
public int read() throws IOException {
int result = 0;
// If there are no more available bytes, mark that we are at the end of the stream.
if (this.virtualAvailable <= 0) {
result = -1;
} else {
// Otherwise, read a byte.
result = this.decryptedContents.read();
}
// If we have not reached the end of the stream, decrement the number of available bytes.
if (result != -1) {
this.virtualAvailable--;
} else {
// If we are at the end of the stream, close it.
close();
this.virtualAvailable = 0;
}
return result;
}
/* (non-Javadoc)
* @see java.io.InputStream#read(byte[], int, int)
*/
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
int numBytesRead;
// If no more bytes are available, do not read any bytes into the buffer
if(this.virtualAvailable <= 0) {
numBytesRead = -1;
} else {
// If the desired read length is greater than the number of available bytes,
// shorten the read length to the number of available bytes.
if(length > this.virtualAvailable) {
// If the number of available bytes is greater than the maximum value of a 32 bit int, then
// read as many bytes as an int can.
length = (this.virtualAvailable < Integer.MAX_VALUE) ? (int)this.virtualAvailable : Integer.MAX_VALUE;
}
// Read bytes into the buffer.
numBytesRead = this.decryptedContents.read(buffer, offset, length);
}
// If we were able to read bytes, decrement the number of bytes available to be read.
if(numBytesRead != -1) {
this.virtualAvailable -= numBytesRead;
} else {
// If we've reached the end of the stream, close it
close();
this.virtualAvailable = 0;
}
return numBytesRead;
}
/* (non-Javadoc)
* @see java.io.InputStream#available()
*/
@Override
public int available() throws IOException {
int available = this.decryptedContents.available();
if(available < this.virtualAvailable) {
return available;
} else {
// Limit the number of bytes available to the number
// of bytes remaining in the range.
return (int)this.virtualAvailable;
}
}
/* (non-Javadoc)
* @see java.io.InputStream#close()
*/
@Override
public void close() throws IOException {
// If not already closed, then close the input stream.
if(!this.closed) {
this.closed = true;
this.decryptedContents.close();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy