/*
* NOTE: This copyright does *not* cover user programs that use HQ program
* services by normal system calls through the application program interfaces
* provided as part of the Hyperic Plug-in Development Kit or the Hyperic Client
* Development Kit - this is merely considered normal use of the program, and
* does *not* fall under the heading of "derived work".
*
* Copyright (C) [2004, 2005, 2006, 2007, 2008], Hyperic, Inc. This file is part
* of HQ.
*
* HQ is free software; you can redistribute it and/or modify it under the terms
* version 2 of the GNU General Public License as published by the Free Software
* Foundation. This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*/
package org.hyperic.util;
import java.io.IOException;
import java.io.InputStream;
/**
* A <code>RandomByteInputStream</code> supplies random bytes corresponding to
* the ascii character range that may be read from the stream. It has an
* associated size and maintains an internal counter to test whether the end of
* the stream is reached during a <code>read</code> operation.
* <p>
* Closing a <tt>RandomByteInputStream</tt> has no effect. The methods in this
* class can be called after the stream has been closed without generating an
* <tt>IOException</tt>.
*
*/
public class RandomByteInputStream extends InputStream {
/**
* The index of the next character to read from the input stream buffer.
* This value should always be nonnegative and not larger than the value of
* <code>count</code>.
*/
protected int pos;
/**
* The number of bytes that can be read from this input stream.
*/
protected int count;
/**
* The random char that will be used to fill up this InputStream
*/
protected char random;
/**
* Creates a <code>RandomByteInputStream</code> of the specified
* <code>length</code>.
*
* @param length the number of bytes available from this input stream.
*/
public RandomByteInputStream(int length) {
this.pos = 0;
this.count = length;
this.random = (char) (Math.random() * ('z' - 'A') + 'A');
}
// initializes the array to a random identical ascii value
private void getRandomBytes(byte[] b ) {
for (int i = 0; i < b.length; i++) {
b[i] = (byte) this.random;
}
}
/**
* Reads the next byte of data from this input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the
* stream has been reached, the value <code>-1</code> is returned.
* <p>
* This <code>read</code> method cannot block.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream has been reached.
*/
public synchronized int read() {
if (pos < count) {
byte[] b = new byte[1];
getRandomBytes(b);
return b[0] & 0xff;
}
else {
return -1;
}
}
/**
* Reads up to <code>len</code> bytes of data into an array of bytes from
* this input stream. If <code>pos</code> equals <code>count</code>,
* then <code>-1</code> is returned to indicate end of file. Otherwise,
* the number <code>k</code> of bytes read is equal to the smaller of
* <code>len</code> and <code>count-pos</code>. If <code>k</code> is
* positive, then k bytes are copied into <code>b[off]</code> through
* <code>b[off+k-1]</code> in the manner performed by
* <code>System.arraycopy</code>. The value <code>k</code> is added
* into <code>pos</code> and <code>k</code> is returned.
* <p>
* This <code>read</code> method cannot block.
*
* @param b the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of the
* stream has been reached.
*/
public synchronized int read(byte[] b, int off, int len) {
if (b == null) {
throw new NullPointerException();
}
else if ((off < 0) || (off > b.length) || (len < 0)
|| ((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (pos >= count) {
return -1;
}
if (pos + len > count) {
len = count - pos;
}
if (len <= 0) {
return 0;
}
byte[] buf = new byte[len];
getRandomBytes(buf);
System.arraycopy(buf, 0, b, off, len);
pos += len;
return len;
}
/**
* Skips <code>n</code> bytes of input from this input stream. Fewer bytes
* might be skipped if the end of the input stream is reached. The actual
* number <code>k</code> of bytes to be skipped is equal to the smaller of
* <code>n</code> and <code>count-pos</code>. The value <code>k</code>
* is added into <code>pos</code> and <code>k</code> is returned.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
*/
public synchronized long skip(long n) {
if (pos + n > count) {
n = count - pos;
}
if (n < 0) {
return 0;
}
pos += n;
return n;
}
/**
* Returns the number of bytes that can be read from this input stream
* without blocking. The value returned is <code>count - pos</code>,
* which is the number of bytes remaining to be read from the input buffer.
*
* @return the number of bytes that can be read from the input stream
* without blocking.
*/
public synchronized int available() {
return count - pos;
}
/**
* Tests if this <code>InputStream</code> supports mark/reset. The
* <code>markSupported</code> method of <code>RandomByteInputStream</code>
* always returns <code>false</code>.
*
*/
public boolean markSupported() {
return false;
}
/**
* The <code>mark</code> method of <code>RandomByteInputStream</code>
* always throws an <code>UnsupportedOperationException</code>.
*
*/
public void mark(int readAheadLimit) {
throw new UnsupportedOperationException("Operation not supported!");
}
/**
* The <code>reset</code> method of <code>RandomByteInputStream</code>
* always throws an <code>UnsupportedOperationException</code>.
*
*/
public synchronized void reset() {
throw new UnsupportedOperationException("Operation not supported!");
}
/**
* Closing a <tt>RandomByteInputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
* <p>
*/
public void close() throws IOException {
}
}