Custom Streams
in Java |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
int
) by performing a bitwise AND
(e.g., i = b & 0x000000FF
)
i = i << 8
)
package io; import java.io.*; /** * For reading from binary streams that were written on a * machine that uses a little-endian scheme. * * For example, C under DOS/Windows uses a little-endian scheme * (i.e., LSB first). * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class LittleEndianInputStream { protected byte[] b1, b2, b4, b8; protected InputStream in; /** * Construct a new LittleEndianInputStream * * @param in The InputStream to use */ public LittleEndianInputStream(InputStream in) { this.in = in; b1 = new byte[1]; b2 = new byte[2]; b4 = new byte[4]; b8 = new byte[8]; } /** * Returns the number of bytes available without blocking * */ public int available() throws IOException { return in.available(); } /** * Closes this input stream */ public void close() throws IOException { in.close(); } /** * Reads an array of bytes * * @param b The buffer into which the data are read * @param off The start offset of the data * @param len The maximum number of bytes read * * @return The number of bytes actually read or -1 if end-of-stream */ public int read(byte[] b, int off, int len) throws IOException { return in.read(b, off, len); } /** * Reads an array of bytes * * @param b The buffer into which the data are read * * @return The number of bytes actually read or -1 if end-of-stream */ public int read(byte[] b) throws IOException { return in.read(b); } /** * Reads an array of bytes * * Note: Unlike read(), this method keeps reading until all of the bytes * are read or an end-of-stream is encountered * * @param b The buffer into which the data are read */ public void readFully(byte[] b) throws IOException { EOFException eofe; int i, n; for (i=0; i < b.length; i+=n) { n = read(b, i, b.length-i); if (n < 0) // End of File Encountered { eofe = new EOFException("EOF in LittleEndianInputStream"); throw(eofe); } } } /** * Reads an int in __big-endian__ format */ public int readInt() throws IOException { readFully(b4); return (b4[0]&0xff) << 24 | (b4[1]&0xff) << 16 | (b4[2]&0xff) << 8 | (b4[3]&0xff); } /** * Reads a 1-byte integer (-128 to 127) * * @return An int with the appropriate value */ public int readInteger1() throws IOException { readFully(b1); return b1[0]; } /** * Reads a 2-byte integer (-32,768 to 32,767) * * @return An int with the appropriate value */ public int readInteger2() throws IOException { readFully(b2); return (int)( (short)( (b2[1] & 0xFF) << 8 | (b2[0] & 0xFF)) ); } /** * Reads a 4-byte integer (-2,147,483,648 to 2,147,483,647) * * @return An int with the appropriate value */ public int readInteger4() throws IOException { readFully(b4); return (b4[3]&0xff) << 24 | (b4[2]&0xff) << 16 | (b4[1]&0xff) << 8 | (b4[0]&0xff); } /** * Reads an 8-byte integer (-9,223,372,036,854,775,808 to * 9,223,372,036,854,775,807) * * @return A long with the appropriate value */ public long readInteger8() throws IOException { readFully(b8); return (long)(b8[7]& 0xFF) << 56 | (long)(b8[6]& 0xFF) << 48 | (long)(b8[5]& 0xFF) << 40 | (long)(b8[4]& 0xFF) << 32 | (long)(b8[3]& 0xFF) << 24 | (long)(b8[2]& 0xFF) << 16 | (long)(b8[1]& 0xFF) << 8 | (long)(b8[0]& 0xFF); } /** * Reads a 4-byte real number * * @return A float with the appropriate value */ public float readReal4() throws IOException { return Float.intBitsToFloat(readInteger4()); } /** * Reads an 8-byte real number * * @return A double with the appropriate value */ public double readReal8() throws IOException { return Double.longBitsToDouble(readInteger8()); } /** * Reads a String * * @param n The number of characters in the String */ public String readString(int n) throws IOException { byte[] b; b = new byte[n]; readFully(b); return new String(b); } /** * Reads an unsigned 1-byte integer (0 to 255) * * @return An int with the appropriate value */ public int readUnsignedInteger1() throws IOException { readFully(b1); return (int)( (b1[0] & 0xFF) ); } /** * Reads an unsigned 2-byte integer (0 to 65,536) * * @return An int with the appropriate value */ public int readUnsignedInteger2() throws IOException { readFully(b2); return ((b2[1] & 0xFF) << 8 | (b2[0] & 0xFF) ); } /** * Reads an unsigned 4-byte integer (0 to 4,294,967,296) * * @return A long with the appropriate value */ public long readUnsignedInteger4() throws IOException { readFully(b4); return ( (b4[3]&0xff) << 24 | (b4[2]&0xff) << 16 | (b4[1]&0xff) << 8 | (b4[0]&0xff) ); } }
package io; import java.io.*; /** * For writing binary streams to be read on a * machine that uses a little-endian scheme. * * For example, C under DOS/Windows uses a little-endian scheme * (i.e., LSB first). * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class LittleEndianOutputStream { protected byte[] b1, b2, b4; protected OutputStream out; /** * Construct a new LittleEndianOutputStream * * @param in The OutputStream to use */ public LittleEndianOutputStream(OutputStream out) { this.out = out; b1 = new byte[1]; b2 = new byte[2]; b4 = new byte[4]; } /** * Closes this output stream */ public void close() throws IOException { out.close(); } /** * Writes a 1-byte integer * * @param i The int to write */ public void writeInteger1(int i) throws IOException { b1[0] = (byte)i; out.write(b1,0,1); } /** * Writes a 2-byte integer * * @param i The int to write */ public void writeInteger2(int i) throws IOException { b2[0] = (byte)i; // LSB b2[1] = (byte)(i >> 8); // MSB out.write(b2,0,2); } /** * Writes a 4-byte integer * * @param i The int to write */ public void writeInteger4(int i) throws IOException { b4[0] = (byte)i; // LSB b4[1] = (byte)(i >> 8); b4[2] = (byte)(i >> 16); b4[3] = (byte)(i >> 24); // MSB out.write(b4,0,4); } /** * Writes an 8-byte integer * * @param l The long to write */ public void writeInteger8(long l) throws IOException { b4[0] = (byte)l; // LSB b4[1] = (byte)(l >> 8); b4[2] = (byte)(l >> 16); b4[3] = (byte)(l >> 24); b4[4] = (byte)(l >> 32); b4[5] = (byte)(l >> 40); b4[6] = (byte)(l >> 48); b4[7] = (byte)(l >> 56); // MSB out.write(b4,0,4); } /** * Writes a 4-byte real number * * @param f The float to write */ public void writeReal4(float f) throws IOException { writeInteger4(Float.floatToIntBits(f)); } /** * Writes an 8-byte real number * * @param d The double to write */ public void writeReal8(double d) throws IOException { writeInteger8(Double.doubleToLongBits(d)); } }
DataInputStream
import java.io.*; /** * An input stream for reading both byte-stream data and * character-stream that is terminated using the HTTP end-of-line * characters ('\r\n') * * @author Prof. David Bernstein, James Madison University * @version 0.0 */ public class HttpInputStream extends DataInputStream { private static final int INITIAL_BUFFER_SIZE = 256; public static final byte CR = (byte)'\r'; //13; public static final byte LF = (byte)'\n'; //10; public static final byte NULL = (byte)'\0'; // 0; private byte[] buffer; private int currentSize; /** * Explicit Value Constructor * * @param is The underlying InputStream */ public HttpInputStream(InputStream is) { super(is); } /** * Add a byte to the current line buffer (increasing the * size of the line buffer if necessary) * * @Param b The byte to add */ private void addToLineBuffer(byte b) { byte[] temp; buffer[currentSize] = b; currentSize++; if (currentSize == buffer.length) { temp = new byte[buffer.length*2]; System.arraycopy(buffer, 0, temp, 0, buffer.length); buffer = temp; } } /** * Reads the input stream, one line at a time. * Lines are terminated either by '\r\n' or by end-of-stream. * * @return A String containing the line */ public String readHttpLine() throws IOException { byte previous; byte[] b; int status, stringLength; String result; // This method will read a byte at a time. It would be much // more efficient to read multiple bytes at a time into a buffer // but this is much simpler. b = new byte[1]; buffer = new byte[INITIAL_BUFFER_SIZE]; currentSize = 0; status = -1; previous = NULL; while (status < 0) { try { readFully(b); // Blocks until a byte is available if ((b[0] == LF) && (previous == CR)) { status = 1; } else { previous = b[0]; addToLineBuffer(b[0]); } } catch (EOFException eofe) { status = 0; } } if (status == 0) stringLength = currentSize; // Terminated by EOS else stringLength = currentSize - 1; // Remove the CR try { // Use the HTTP "standard" character set result = new String(buffer, 0, stringLength, "ISO-8859-1"); } catch (UnsupportedEncodingException uee) { // Use the default character set result = new String(buffer, 0, stringLength); } return result; } }
PrintStream
import java.io.*; /** * A PrintStream that can be used for writing HTTP requests * and responses * * @author Prof. David Bernstein, James Madison University * @version 0.0 */ public class HttpOutputStream extends PrintStream { /** * Explicit Value Constructor * * @param os The underlying OutputStream to use */ public HttpOutputStream(OutputStream os) { super(os, false); } /** * Print an End-Of-Line marker */ public void printEOL() { print("\r\n"); } /** * Print a line (using the HTTP End-Of-Line marker) * * @param line The line to print */ public void printHttpLine(String line) { print(line); print("\r\n"); } /** * Print an appropriately formatted and terminated * header line * * @param name The name * @param value The corresponding value */ public void printHeaderLine(String name, String value) { print(name); print(":"); print(value); printEOL(); } }