package ua.stu.scplib.attribute;
import java.io.*;
/**
* <p>A class that extends {@link java.io.FilterInputStream FilterInputStream} by adding
* the concept of little and big endian binary value encoding, and supplies functions
* for reading various sized integer and floating point words.</p>
*
* @see com.pixelmed.dicom.BinaryOutputStream
*
* @author dclunie
*/
public class BinaryInputStream extends FilterInputStream {
/***/
boolean bigEndian;
/***/
byte buffer[];
/**/
File file;
/**
* @param big
*/
void localInit(boolean big) {
bigEndian=big;
buffer=new byte[8];
}
/**
* <p>Construct a byte ordered stream from the supplied file.</p>
*
* <p>The byte order may be changed later.</p>
*
* @param file the file to read from
* @param big true if big endian, false if little endian
*/
public BinaryInputStream(File file,boolean big) throws FileNotFoundException {
super(new BufferedInputStream(new FileInputStream(file)));
this.file=file;
localInit(big);
}
/**
* <p>Construct a byte ordered stream from the supplied stream.</p>
*
* <p>The byte order may be changed later.</p>
*
* @param i the input stream to read from
* @param big true if big endian, false if little endian
*/
public BinaryInputStream(InputStream i,boolean big) {
super(i);
this.file=null;
localInit(big);
}
/**
* <p>Get the file associated with this stream.</p>
*
* @return file the file, or null if not a file input stream
*/
public File getFile() { return file; }
/**
* <p>Is the stream byte order big endian ?</p>
*
* @return true if big endian, false if little endian
*/
public boolean isBigEndian() { return bigEndian; }
/**
* <p>Is the stream byte order little endian ?</p>
*
* @return true if little endian, false if big endian
*/
public boolean isLittleEndian() { return !bigEndian; }
/**
* <p>Set the stream byte order to big endian.</p>
*/
public void setBigEndian() { bigEndian=true; }
/**
* <p>Set the stream byte order to little endian.</p>
*/
public void setLittleEndian() { bigEndian=false; }
/**
* <p>Set the stream byte order to that specified.</p>
*
* @param big true if to set to big endian, false if little endian
*/
public void setEndian(boolean big) {
bigEndian=big;
}
/***/
final int extractUnsigned8() {
return ((int)buffer[0])&0xff;
}
/***/
final int extractUnsigned16() {
int v1 = ((int)buffer[0])&0xff;
int v2 = ((int)buffer[1])&0xff;
return bigEndian
? (v1 << 8) | v2
: (v2 << 8) | v1;
}
/***/
final short extractSigned16() {
short v1 = (short)(buffer[0]&0xff);
short v2 = (short)(buffer[1]&0xff);
return (short) (bigEndian
? (v1 << 8) | v2
: (v2 << 8) | v1);
}
/***/
final long extractUnsigned32() {
long v1 = ((long)buffer[0])&0xff;
long v2 = ((long)buffer[1])&0xff;
long v3 = ((long)buffer[2])&0xff;
long v4 = ((long)buffer[3])&0xff;
return bigEndian
? (((((v1 << 8) | v2) << 8) | v3) << 8) | v4
: (((((v4 << 8) | v3) << 8) | v2) << 8) | v1;
}
/***/
final int extractSigned32() {
int v1 = ((int)buffer[0])&0xff;
int v2 = ((int)buffer[1])&0xff;
int v3 = ((int)buffer[2])&0xff;
int v4 = ((int)buffer[3])&0xff;
return bigEndian
? (((((v1 << 8) | v2) << 8) | v3) << 8) | v4
: (((((v4 << 8) | v3) << 8) | v2) << 8) | v1;
}
/***/
final long extractUnsigned64() {
long v1 = ((long)buffer[0])&0xff;
long v2 = ((long)buffer[1])&0xff;
long v3 = ((long)buffer[2])&0xff;
long v4 = ((long)buffer[3])&0xff;
long v5 = ((long)buffer[4])&0xff;
long v6 = ((long)buffer[5])&0xff;
long v7 = ((long)buffer[6])&0xff;
long v8 = ((long)buffer[7])&0xff;
return bigEndian
? (((((((((((((v1 << 8) | v2) << 8) | v3) << 8) | v4) << 8) | v5) << 8) | v6) << 8) | v7) << 8) | v8
: (((((((((((((v8 << 8) | v7) << 8) | v6) << 8) | v5) << 8) | v4) << 8) | v3) << 8) | v2) << 8) | v1;
}
/**
* <p>Read as many bytes as requested, unless an exception occurs.</p>
*
* @param b buffer to read into
* @param offset offset (from 0) in buffer to read into
* @param length number of bytes to read (no more and no less)
* @exception IOException
*/
public void readInsistently(byte[] b,int offset,int length) throws IOException {
int remaining = length;
while (remaining > 0) {
//System.err.println("readInsistently(): looping offset="+offset+" remaining="+remaining);
int bytesReceived = in.read(b,offset,remaining);
//System.err.println("readInsistently(): asked for ="+remaining+" received="+bytesReceived);
if (bytesReceived == -1) throw new IOException("read failed with "+remaining+" bytes remaining to be read, wanted "+length);
remaining-=bytesReceived;
offset+=bytesReceived;
}
}
/**
* <p>Skip as many bytes as requested, unless an exception occurs.</p>
*
* @param length number of bytes to read (no more and no less)
* @exception IOException
*/
public void skipInsistently(long length) throws IOException {
long remaining = length;
while (remaining > 0) {
//System.err.println("skipInsistently(): looping remaining="+remaining);
long bytesSkipped = in.skip(remaining);
//System.err.println("skipInsistently(): asked for ="+remaining+" got="+bytesSkipped);
if (bytesSkipped <= 0) throw new IOException("skip failed with "+remaining+" bytes remaining to be skipped, wanted "+length);
remaining-=bytesSkipped;
}
}
/**
* <p>Read one unsigned integer 8 bit value.</p>
*
* @return an int containing an unsigned value
* @exception IOException
*/
public final int readUnsigned8() throws IOException {
readInsistently(buffer,0,1);
return extractUnsigned8();
}
/**
* <p>Read one unsigned integer 16 bit value.</p>
*
* @return an int containing an unsigned value
* @exception IOException
*/
public final int readUnsigned16() throws IOException {
readInsistently(buffer,0,2);
return extractUnsigned16();
}
/**
* <p>Read one signed integer 16 bit value.</p>
*
* @return an int containing an unsigned value
* @exception IOException
*/
public final int readSigned16() throws IOException {
readInsistently(buffer,0,2);
return extractSigned16();
}
/**
* <p>Read one unsigned integer 32 bit value.</p>
*
* @return a long containing an unsigned value
* @exception IOException
*/
public final long readUnsigned32() throws IOException {
readInsistently(buffer,0,4);
return extractUnsigned32();
}
/**
* <p>Read one signed integer 32 bit value.</p>
*
* @return an int containing an signed value
* @exception IOException
*/
public final int readSigned32() throws IOException {
readInsistently(buffer,0,4);
return extractSigned32();
}
/**
* <p>Read one floating point 32 bit value.</p>
*
* @return a float value
* @exception IOException
*/
public final float readFloat() throws IOException {
readInsistently(buffer,0,4);
int binary = (int)(extractUnsigned32());
return Float.intBitsToFloat(binary);
}
/**
* <p>Read one floating point 64 bit value.</p>
*
* @return a double value
* @exception IOException
*/
public final double readDouble() throws IOException {
readInsistently(buffer,0,8);
long binary = extractUnsigned64();
return Double.longBitsToDouble(binary);
}
/**
* <p>Read an array of unsigned integer 16 bit values.</p>
*
* @param w an array of sufficient size in which to return the values read
* @param len the number of 16 bit values to read
* @exception IOException
*/
public final void readUnsigned16(short[] w,int len) throws IOException {
readUnsigned16(w,0,len);
}
/**
* <p>Read an array of unsigned integer 16 bit values.</p>
*
* @param w an array of sufficient size in which to return the values read
* @param offset the offset in the array at which to begin storing values
* @param len the number of 16 bit values to read
* @exception IOException
*/
public final void readUnsigned16(short[] w,int offset,int len) throws IOException {
int blen = len*2;
byte b[] = new byte[blen];
readInsistently(b,0,blen);
int bcount=0;
int wcount=0;
//long starttime=new Date().getTime();
//System.err.println("readUnsigned16: ready to convert at: 0");
if (bigEndian) {
while (wcount<len) {
int highByte=((int)b[bcount++])&0xff;
int lowByte=((int)b[bcount++])&0xff;
short value=(short)((highByte<<8) + lowByte);
w[offset+wcount++]=(short)value;
}
}
else {
//while (wcount<len) {
for (;wcount<len;++wcount) {
//int lowByte=((int)b[bcount++])&0xff;
//int highByte=((int)b[bcount++])&0xff;
//short value=(short)((highByte<<8) + lowByte);
//w[wcount++]=(short)value;
//w[wcount++]=(short)((b[bcount+1]<<8) + (b[bcount]&0xff));
//w[wcount++]=(short)((b[bcount++]&0xff) + (b[bcount++]<<8)); // assumes left to right evaluation
w[offset+wcount]=(short)((b[bcount++]&0xff) + (b[bcount++]<<8)); // assumes left to right evaluation
//bcount++; bcount++;
//bcount+=2;
}
}
//System.err.println("readUnsigned16: exit at: "+(new Date().getTime()-starttime));
}
/**
* <p>Read an array of floating point 32 bit values.</p>
*
* @param f an array of sufficient size in which to return the values read
* @param len the number of 32 bit values to read
* @exception IOException
*/
public final void readFloat(float[] f,int len) throws IOException {
for (int i=0; i<len; ++i) f[i]=readFloat();
}
/**
* <p>Read interleaved complex floating point 32 bit value pairs into real and imaginary arrays.</p>
*
* @param freal an array of sufficient size in which to return the real values read, may be null if don't want real values
* @param fimaginary an array of sufficient size in which to return the real values read, may be null if don't want imaginary values
* @param len the number of 32 bit values to read
* @exception IOException
*/
public final void readComplexFloat(float[] freal,float[] fimaginary,int len) throws IOException {
for (int i=0; i<len; ++i) {
float vreal=readFloat();
float vimaginary=readFloat();
if (freal != null) freal[i]=vreal;
if (fimaginary != null) fimaginary[i]=vimaginary;
}
}
/**
* <p>Read an array of floating point 64 bit values.</p>
*
* @param f an array of sufficient size in which to return the values read
* @param len the number of 64 bit values to read
* @exception IOException
*/
public final void readDouble(double[] f,int len) throws IOException {
for (int i=0; i<len; ++i) f[i]=readDouble();
}
/**
* <p>Read interleaved complex floating point 64 bit value pairs into real and imaginary arrays.</p>
*
* @param freal an array of sufficient size in which to return the real values read, may be null if don't want real values
* @param fimaginary an array of sufficient size in which to return the real values read, may be null if don't want imaginary values
* @param len the number of 64 bit values to read
* @exception IOException
*/
public final void readComplexDouble(double[] freal,double[] fimaginary,int len) throws IOException {
for (int i=0; i<len; ++i) {
double vreal=readDouble();
double vimaginary=readDouble();
if (freal != null) freal[i]=vreal;
if (fimaginary != null) fimaginary[i]=vimaginary;
}
}
/**
* @param bval
*/
final void setBufferForTest(byte[] bval) {
buffer=bval;
}
/**
* <p>For testing.</p>
*
* @param arg
*/
public static void main(String arg[]) {
// little endian ...
BinaryInputStream i=null;
try {
i = new BinaryInputStream(new FileInputStream(arg[0]),false);
} catch (Exception e) {
System.err.println(e);
System.exit(0);
}
byte testBuffer[] = new byte[4];
i.setBufferForTest(testBuffer);
testBuffer[0]=(byte)0xff;
testBuffer[1]=(byte)0x00;
testBuffer[2]=(byte)0x00;
testBuffer[3]=(byte)0x00;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[1]=(byte)0xff;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[2]=(byte)0xff;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[3]=(byte)0xff;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[0]=(byte)0x7f;
testBuffer[1]=(byte)0x00;
testBuffer[2]=(byte)0x00;
testBuffer[3]=(byte)0x00;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[1]=(byte)0x7f;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[2]=(byte)0x7f;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[3]=(byte)0x7f;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
// big endian ...
try {
i = new BinaryInputStream(new FileInputStream(arg[0]),true);
} catch (Exception e) {
System.err.println(e);
System.exit(0);
}
i.setBufferForTest(testBuffer);
testBuffer[3]=(byte)0xff;
testBuffer[2]=(byte)0x00;
testBuffer[1]=(byte)0x00;
testBuffer[0]=(byte)0x00;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[2]=(byte)0xff;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[1]=(byte)0xff;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[0]=(byte)0xff;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[3]=(byte)0x7f;
testBuffer[2]=(byte)0x00;
testBuffer[1]=(byte)0x00;
testBuffer[0]=(byte)0x00;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[2]=(byte)0x7f;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[1]=(byte)0x7f;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
testBuffer[0]=(byte)0x7f;
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned8()));
System.err.println("Extracted 0x"+Integer.toHexString(i.extractUnsigned16()));
System.err.println("Extracted 0x"+ Long.toHexString(i.extractUnsigned32()));
}
}