BinaryIO.java

  1. package gov.usgs.earthquake.product.io;

  2. import java.io.EOFException;
  3. import java.io.IOException;
  4. import java.io.OutputStream;
  5. import java.io.InputStream;

  6. import java.nio.ByteBuffer;
  7. import java.nio.charset.StandardCharsets;
  8. import java.util.Date;

  9. public class BinaryIO {

  10.     /**
  11.      * Writes an int to the OutputStream buffer
  12.      * @param in an int to write
  13.      * @param out the OutputStream
  14.      * @throws IOException if IO error occurs
  15.      */
  16.     public void writeInt(final int in, final OutputStream out)
  17.             throws IOException {
  18.         out.write(ByteBuffer.allocate(4).putInt(in).array());
  19.     }

  20.     /**
  21.      * Writes an long to the OutputStream buffer
  22.      * @param in an long to write
  23.      * @param out the OutputStream
  24.      * @throws IOException if IO error occurs
  25.      */
  26.     public void writeLong(final long in, final OutputStream out)
  27.             throws IOException {
  28.         out.write(ByteBuffer.allocate(8).putLong(in).array());
  29.     }

  30.     /**
  31.      * Writes an array of bytes to the OutputStream buffer
  32.      * @param toWrite an array of bytes to write
  33.      * @param out the OutputStream
  34.      * @throws IOException if IO error occurs
  35.      */
  36.     public void writeBytes(final byte[] toWrite, final OutputStream out)
  37.             throws IOException {
  38.         // length of string
  39.         writeInt(toWrite.length, out);
  40.         // string
  41.         out.write(toWrite);
  42.     }

  43.     /**
  44.      * Writes a string to the OutputStream buffer
  45.      * @param toWrite a string to write
  46.      * @param out the OutputStream
  47.      * @throws IOException if IO error occurs
  48.      */
  49.     public void writeString(final String toWrite, final OutputStream out)
  50.             throws IOException {
  51.         writeBytes(toWrite.getBytes(StandardCharsets.UTF_8), out);
  52.     }

  53.     /**
  54.      * Writes a date to the OutputStream buffer
  55.      * @param toWrite a date to write
  56.      * @param out the OutputStream
  57.      * @throws IOException if IO error occurs
  58.      */
  59.     public void writeDate(final Date toWrite, final OutputStream out)
  60.             throws IOException {
  61.         writeLong(toWrite.getTime(), out);
  62.     }

  63.     /**
  64.      * Writes a long to the OutputStream buffer
  65.      * @param length a long to write
  66.      * @param in an input stream
  67.      * @param out the OutputStream
  68.      * @throws IOException if IO error occurs
  69.      */
  70.     public void writeStream(final long length, final InputStream in,
  71.             final OutputStream out) throws IOException {
  72.         writeLong(length, out);

  73.         // transfer stream bytes
  74.         int read = -1;
  75.         byte[] bytes = new byte[1024];
  76.         // read no more than length bytes
  77.         while ((read = in.read(bytes)) != -1) {
  78.             out.write(bytes, 0, read);
  79.         }
  80.     }

  81.     /**
  82.      * Reads 4 bytes from the InputStream
  83.      * @param in InputStream
  84.      * @return an int
  85.      * @throws IOException if IO Error occurs
  86.      */
  87.     public int readInt(final InputStream in) throws IOException {
  88.         byte[] buffer = new byte[4];
  89.         readFully(buffer, in);
  90.         return ByteBuffer.wrap(buffer).getInt();
  91.     }

  92.     /**
  93.      * Reads 8 bytes from the InputStream
  94.      * @param in InputStream
  95.      * @return a long
  96.      * @throws IOException if IO Error occurs
  97.      */
  98.     public long readLong(final InputStream in) throws IOException {
  99.         byte[] buffer = new byte[8];
  100.         readFully(buffer, in);
  101.         return ByteBuffer.wrap(buffer).getLong();
  102.     }

  103.     /**
  104.      * Reads a byte array from the InputStream
  105.      * @param in InputStream
  106.      * @return Byte[]
  107.      * @throws IOException if IO Error occurs
  108.      */
  109.     public byte[] readBytes(final InputStream in) throws IOException {
  110.         int length = readInt(in);
  111.         byte[] buffer = new byte[length];
  112.         readFully(buffer, in);
  113.         return buffer;
  114.     }


  115.     /**
  116.      * Reads string from the InputStream
  117.      * @param in InputStream
  118.      * @return a string
  119.      * @throws IOException if IO Error occurs
  120.      */
  121.     public String readString(final InputStream in) throws IOException {
  122.         return this.readString(in, -1);
  123.     }

  124.     /**
  125.      * Reads string with a max length from the InputStream
  126.      * @param in InputStream
  127.      * @param maxLength of string
  128.      * @return an string
  129.      * @throws IOException if IO Error occurs
  130.      */
  131.     public String readString(final InputStream in, final int maxLength) throws IOException {
  132.         int length = readInt(in);
  133.         if (maxLength > 0 && length > maxLength) {
  134.             throw new IOException("request string length " + length + " greater than maxLength " + maxLength);
  135.         }
  136.         byte[] buffer = new byte[length];
  137.         readFully(buffer, in);
  138.         return new String(buffer, StandardCharsets.UTF_8);
  139.     }

  140.     /**
  141.      * Reads date from the InputStream
  142.      * @param in InputStream
  143.      * @return a date
  144.      * @throws IOException if IO Error occurs
  145.      */
  146.     public Date readDate(final InputStream in) throws IOException {
  147.         return new Date(readLong(in));
  148.     }

  149.     /**
  150.      * Reads stream
  151.      * @param in InputStream
  152.      * @param out OutputStream
  153.      * @throws IOException if IO Error occurs
  154.      */
  155.     public void readStream(final InputStream in, final OutputStream out)
  156.             throws IOException {
  157.         long length = readLong(in);
  158.         readStream(length, in, out);
  159.     }

  160.     /**
  161.      * Function called by previous readStream
  162.      * Used to read whole stream
  163.      * @param length length of inputstream
  164.      * @param in input stream
  165.      * @param out output stream
  166.      * @throws IOException if io error occurs
  167.      */
  168.     public void readStream(final long length, final InputStream in,
  169.             final OutputStream out) throws IOException {
  170.         long remaining = length;

  171.         // transfer stream bytes, not going over total
  172.         int read = -1;
  173.         byte[] bytes = new byte[1024];
  174.         int readSize = bytes.length;

  175.         while (remaining > 0) {
  176.             if (remaining < readSize) {
  177.                 // don't read past end of stream
  178.                 readSize = (int) remaining;
  179.             }

  180.             // read next chunk
  181.             read = in.read(bytes, 0, readSize);
  182.             if (read == -1) {
  183.                 // shouldn't be at eof, since reading length specified in stream
  184.                 throw new EOFException();
  185.             }
  186.             // track how much has been read
  187.             remaining -= read;
  188.             // transfer to out stream
  189.             out.write(bytes, 0, read);
  190.         }
  191.     }

  192.     /**
  193.      * Function used by other read funcs
  194.      * Reads from input stream until buffer is full
  195.      * @param buffer byte[]
  196.      * @param in inputstream
  197.      * @throws IOException if IO error occurs
  198.      */
  199.     protected void readFully(final byte[] buffer, final InputStream in)
  200.             throws IOException {
  201.         int length = buffer.length;
  202.         int totalRead = 0;
  203.         int read = -1;

  204.         while ((read = in.read(buffer, totalRead, length - totalRead)) != -1) {
  205.             totalRead += read;
  206.             if (totalRead == length) {
  207.                 break;
  208.             }
  209.         }

  210.         if (totalRead != length) {
  211.             throw new IOException("EOF before buffer could be readFully, read=" + totalRead + ", expected=" + length);
  212.         }
  213.     }

  214. }