diff --git a/src/main/java/org/warp/commonutils/stream/SafeDataInputStream.java b/src/main/java/org/warp/commonutils/stream/SafeDataInputStream.java new file mode 100644 index 0000000..3e84e5c --- /dev/null +++ b/src/main/java/org/warp/commonutils/stream/SafeDataInputStream.java @@ -0,0 +1,580 @@ +/* + * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +package org.warp.commonutils.stream; + +import java.io.DataInput; + +/** + * A data input stream lets an application read primitive Java data + * types from an underlying input stream in a machine-independent + * way. An application uses a data output stream to write data that + * can later be read by a data input stream. + *
+ * DataInputStream is not necessarily safe for multithreaded access. + * Thread safety is optional and is the responsibility of users of + * methods in this class. + * + * @author Arthur van Hoff + * @see java.io.DataOutputStream + * @since 1.0 + */ +public class SafeDataInputStream extends SafeFilterInputStream implements DataInput { + + /** + * Creates a DataInputStream that uses the specified + * underlying InputStream. + * + * @param in the specified input stream + */ + public SafeDataInputStream(SafeInputStream in) { + super(in); + } + + /** + * working arrays initialized on demand by readUTF + */ + private byte bytearr[] = new byte[80]; + private char chararr[] = new char[80]; + + /** + * Reads some number of bytes from the contained input stream and + * stores them into the buffer array {@code b}. The number of + * bytes actually read is returned as an integer. This method blocks + * until input data is available, end of file is detected, or an + * exception is thrown. + * + *
If {@code b} is null, a {@code NullPointerException} is + * thrown. If the length of {@code b} is zero, then no bytes are + * read and {@code 0} is returned; otherwise, there is an attempt + * to read at least one byte. If no byte is available because the + * stream is at end of file, the value {@code -1} is returned; + * otherwise, at least one byte is read and stored into {@code b}. + * + *
The first byte read is stored into element {@code b[0]}, the + * next one into {@code b[1]}, and so on. The number of bytes read + * is, at most, equal to the length of {@code b}. Let {@code k} + * be the number of bytes actually read; these bytes will be stored in + * elements {@code b[0]} through {@code b[k-1]}, leaving + * elements {@code b[k]} through {@code b[b.length-1]} + * unaffected. + * + *
The {@code read(b)} method has the same effect as: + *
+ * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * {@code -1} if there is no more data because the end + * of the stream has been reached. + * @see SafeFilterInputStream#in + * @see java.io.InputStream#read(byte[], int, int) + */ + public final int read(byte b[]) { + return in.read(b, 0, b.length); + } + + /** + * Reads up to {@code len} bytes of data from the contained + * input stream into an array of bytes. An attempt is made to read + * as many as {@code len} bytes, but a smaller number may be read, + * possibly zero. The number of bytes actually read is returned as an + * integer. + * + *+ * read(b, 0, b.length) + *
This method blocks until input data is available, end of file is + * detected, or an exception is thrown. + * + *
If {@code len} is zero, then no bytes are read and + * {@code 0} is returned; otherwise, there is an attempt to read at + * least one byte. If no byte is available because the stream is at end of + * file, the value {@code -1} is returned; otherwise, at least one + * byte is read and stored into {@code b}. + * + *
The first byte read is stored into element {@code b[off]}, the + * next one into {@code b[off+1]}, and so on. The number of bytes read + * is, at most, equal to {@code len}. Let k be the number of + * bytes actually read; these bytes will be stored in elements + * {@code b[off]} through {@code b[off+}k{@code -1]}, + * leaving elements {@code b[off+}k{@code ]} through + * {@code b[off+len-1]} unaffected. + * + *
In every case, elements {@code b[0]} through + * {@code b[off]} and elements {@code b[off+len]} through + * {@code b[b.length-1]} are unaffected. + * + * @param b the buffer into which the data is read. + * @param off the start offset in the destination array {@code b} + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * {@code -1} if there is no more data because the end + * of the stream has been reached. + * @throws NullPointerException If {@code b} is {@code null}. + * @throws IndexOutOfBoundsException If {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off} + * @see SafeFilterInputStream#in + * @see java.io.InputStream#read(byte[], int, int) + */ + public final int read(byte b[], int off, int len) { + return in.read(b, off, len); + } + + /** + * See the general contract of the {@code readFully} + * method of {@code DataInput}. + *
+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @param b the buffer into which the data is read. + * @throws NullPointerException if {@code b} is {@code null}. + * @see SafeFilterInputStream#in + */ + public final void readFully(byte b[]) { + readFully(b, 0, b.length); + } + + /** + * See the general contract of the {@code readFully} + * method of {@code DataInput}. + *
+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @param b the buffer into which the data is read. + * @param off the start offset in the data array {@code b}. + * @param len the number of bytes to read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off}. + * @see SafeFilterInputStream#in + */ + public final void readFully(byte b[], int off, int len) { + if (len < 0) + throw new IndexOutOfBoundsException(); + int n = 0; + while (n < len) { + int count = in.read(b, off + n, len - n); + if (count < 0) + throw new IndexOutOfBoundsException(); + n += count; + } + } + + /** + * See the general contract of the {@code skipBytes} + * method of {@code DataInput}. + *
+ * Bytes for this operation are read from the contained
+ * input stream.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ */
+ public final int skipBytes(int n) {
+ int total = 0;
+ int cur = 0;
+
+ while ((total
+ * Bytes for this operation are read from the contained
+ * input stream.
+ *
+ * @return the {@code boolean} value read.
+ * @see SafeFilterInputStream#in
+ */
+ public final boolean readBoolean() {
+ int ch = in.read();
+ if (ch < 0)
+ throw new IndexOutOfBoundsException();
+ return (ch != 0);
+ }
+
+ /**
+ * See the general contract of the {@code readByte}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next byte of this input stream as a signed 8-bit
+ * {@code byte}.
+ * @see SafeFilterInputStream#in
+ */
+ public final byte readByte() {
+ int ch = in.read();
+ if (ch < 0)
+ throw new IndexOutOfBoundsException();
+ return (byte)(ch);
+ }
+
+ /**
+ * See the general contract of the {@code readUnsignedByte}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next byte of this input stream, interpreted as an
+ * unsigned 8-bit number.
+ * @see SafeFilterInputStream#in
+ */
+ public final int readUnsignedByte() {
+ int ch = in.read();
+ if (ch < 0)
+ throw new IndexOutOfBoundsException();
+ return ch;
+ }
+
+ /**
+ * See the general contract of the {@code readShort}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next two bytes of this input stream, interpreted as a
+ * signed 16-bit number.
+ * @see SafeFilterInputStream#in
+ */
+ public final short readShort() {
+ int ch1 = in.read();
+ int ch2 = in.read();
+ if ((ch1 | ch2) < 0)
+ throw new IndexOutOfBoundsException();
+ return (short)((ch1 << 8) + (ch2 << 0));
+ }
+
+ /**
+ * See the general contract of the {@code readUnsignedShort}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next two bytes of this input stream, interpreted as an
+ * unsigned 16-bit integer.
+ * @see SafeFilterInputStream#in
+ */
+ public final int readUnsignedShort() {
+ int ch1 = in.read();
+ int ch2 = in.read();
+ if ((ch1 | ch2) < 0)
+ throw new IndexOutOfBoundsException();
+ return (ch1 << 8) + (ch2 << 0);
+ }
+
+ /**
+ * See the general contract of the {@code readChar}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next two bytes of this input stream, interpreted as a
+ * {@code char}.
+ * @see SafeFilterInputStream#in
+ */
+ public final char readChar() {
+ int ch1 = in.read();
+ int ch2 = in.read();
+ if ((ch1 | ch2) < 0)
+ throw new IndexOutOfBoundsException();
+ return (char)((ch1 << 8) + (ch2 << 0));
+ }
+
+ /**
+ * See the general contract of the {@code readInt}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next four bytes of this input stream, interpreted as an
+ * {@code int}.
+ * @see SafeFilterInputStream#in
+ */
+ public final int readInt() {
+ int ch1 = in.read();
+ int ch2 = in.read();
+ int ch3 = in.read();
+ int ch4 = in.read();
+ if ((ch1 | ch2 | ch3 | ch4) < 0)
+ throw new IndexOutOfBoundsException();
+ return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
+ }
+
+ private byte readBuffer[] = new byte[8];
+
+ /**
+ * See the general contract of the {@code readLong}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next eight bytes of this input stream, interpreted as a
+ * {@code long}.
+ * @see SafeFilterInputStream#in
+ */
+ public final long readLong() {
+ readFully(readBuffer, 0, 8);
+ return (((long)readBuffer[0] << 56) +
+ ((long)(readBuffer[1] & 255) << 48) +
+ ((long)(readBuffer[2] & 255) << 40) +
+ ((long)(readBuffer[3] & 255) << 32) +
+ ((long)(readBuffer[4] & 255) << 24) +
+ ((readBuffer[5] & 255) << 16) +
+ ((readBuffer[6] & 255) << 8) +
+ ((readBuffer[7] & 255) << 0));
+ }
+
+ /**
+ * See the general contract of the {@code readFloat}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next four bytes of this input stream, interpreted as a
+ * {@code float}.
+ * @see SafeDataInputStream#readInt()
+ * @see java.lang.Float#intBitsToFloat(int)
+ */
+ public final float readFloat() {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * See the general contract of the {@code readDouble}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next eight bytes of this input stream, interpreted as a
+ * {@code double}.
+ * @see SafeDataInputStream#readLong()
+ * @see java.lang.Double#longBitsToDouble(long)
+ */
+ public final double readDouble() {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ private char lineBuffer[];
+
+ /**
+ * See the general contract of the {@code readLine}
+ * method of {@code DataInput}.
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @deprecated This method does not properly convert bytes to characters.
+ * As of JDK 1.1, the preferred way to read lines of text is via the
+ * {@code BufferedReader.readLine()} method. Programs that use the
+ * {@code DataInputStream} class to read lines can be converted to use
+ * the {@code BufferedReader} class by replacing code of the form:
+ *
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return a Unicode string.
+ * @see SafeDataInputStream#readUTF(SafeDataInputStream)
+ */
+ public final String readUTF() {
+ return readUTF(this);
+ }
+
+ /**
+ * Reads from the
+ * stream {@code in} a representation
+ * of a Unicode character string encoded in
+ * modified UTF-8 format;
+ * this string of characters is then returned as a {@code String}.
+ * The details of the modified UTF-8 representation
+ * are exactly the same as for the {@code readUTF}
+ * method of {@code DataInput}.
+ *
+ * @param in a data input stream.
+ * @return a Unicode string.
+ * @see SafeDataInputStream#readUnsignedShort()
+ */
+ public static final String readUTF(SafeDataInputStream in) {
+ int utflen = in.readUnsignedShort();
+ byte[] bytearr = null;
+ char[] chararr = null;
+ SafeDataInputStream dis = in;
+ if (dis.bytearr.length < utflen){
+ dis.bytearr = new byte[utflen*2];
+ dis.chararr = new char[utflen*2];
+ }
+ chararr = dis.chararr;
+ bytearr = dis.bytearr;
+
+ int c, char2, char3;
+ int count = 0;
+ int chararr_count=0;
+
+ in.readFully(bytearr, 0, utflen);
+
+ while (count < utflen) {
+ c = (int) bytearr[count] & 0xff;
+ if (c > 127) break;
+ count++;
+ chararr[chararr_count++]=(char)c;
+ }
+
+ while (count < utflen) {
+ c = (int) bytearr[count] & 0xff;
+ switch (c >> 4) {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ /* 0xxxxxxx*/
+ count++;
+ chararr[chararr_count++]=(char)c;
+ break;
+ case 12: case 13:
+ /* 110x xxxx 10xx xxxx*/
+ count += 2;
+ if (count > utflen)
+ throw new IllegalArgumentException(
+ "malformed input: partial character at end");
+ char2 = bytearr[count-1];
+ if ((char2 & 0xC0) != 0x80)
+ throw new IllegalArgumentException(
+ "malformed input around byte " + count);
+ chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
+ (char2 & 0x3F));
+ break;
+ case 14:
+ /* 1110 xxxx 10xx xxxx 10xx xxxx */
+ count += 3;
+ if (count > utflen)
+ throw new IllegalArgumentException(
+ "malformed input: partial character at end");
+ char2 = bytearr[count-2];
+ char3 = bytearr[count-1];
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ throw new IllegalArgumentException(
+ "malformed input around byte " + (count-1));
+ chararr[chararr_count++]=(char)(((c & 0x0F) << 12) |
+ ((char2 & 0x3F) << 6) |
+ ((char3 & 0x3F) << 0));
+ break;
+ default:
+ /* 10xx xxxx, 1111 xxxx */
+ throw new IllegalArgumentException(
+ "malformed input around byte " + count);
+ }
+ }
+ // The number of chars produced may be less than utflen
+ return new String(chararr, 0, chararr_count);
+ }
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafeDataOutput.java b/src/main/java/org/warp/commonutils/stream/SafeDataOutput.java
new file mode 100644
index 0000000..a48aa34
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafeDataOutput.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+package org.warp.commonutils.stream;
+
+/**
+ * The {@code SafeDataOutput} interface provides
+ * for converting data from any of the Java
+ * primitive types to a series of bytes and
+ * writing these bytes to a binary stream.
+ * There is also a facility for converting
+ * a {@code String} into
+ * modified UTF-8
+ * format and writing the resulting series
+ * of bytes.
+ *
+ * For all the methods in this interface that
+ * write bytes, it is generally true that if
+ * a byte cannot be written for any reason,
+ * an {@code IOException} is thrown.
+ *
+ * @author Frank Yellin
+ * @see java.io.DataInput
+ * @see java.io.DataOutputStream
+ * @since 1.0
+ */
+public interface SafeDataOutput {
+ /**
+ * Writes to the output stream the eight
+ * low-order bits of the argument {@code b}.
+ * The 24 high-order bits of {@code b}
+ * are ignored.
+ *
+ * @param b the byte to be written.
+ */
+ void write(int b);
+
+ /**
+ * Writes to the output stream all the bytes in array {@code b}.
+ * If {@code b} is {@code null},
+ * a {@code NullPointerException} is thrown.
+ * If {@code b.length} is zero, then
+ * no bytes are written. Otherwise, the byte
+ * {@code b[0]} is written first, then
+ * {@code b[1]}, and so on; the last byte
+ * written is {@code b[b.length-1]}.
+ *
+ * @param b the data.
+ */
+ void write(byte b[]);
+
+ /**
+ * Writes {@code len} bytes from array
+ * {@code b}, in order, to
+ * the output stream. If {@code b}
+ * is {@code null}, a {@code NullPointerException}
+ * is thrown. If {@code off} is negative,
+ * or {@code len} is negative, or {@code off+len}
+ * is greater than the length of the array
+ * {@code b}, then an {@code IndexOutOfBoundsException}
+ * is thrown. If {@code len} is zero,
+ * then no bytes are written. Otherwise, the
+ * byte {@code b[off]} is written first,
+ * then {@code b[off+1]}, and so on; the
+ * last byte written is {@code b[off+len-1]}.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ */
+ void write(byte b[], int off, int len);
+
+ /**
+ * Writes a {@code boolean} value to this output stream.
+ * If the argument {@code v}
+ * is {@code true}, the value {@code (byte)1}
+ * is written; if {@code v} is {@code false},
+ * the value {@code (byte)0} is written.
+ * The byte written by this method may
+ * be read by the {@code readBoolean}
+ * method of interface {@code DataInput},
+ * which will then return a {@code boolean}
+ * equal to {@code v}.
+ *
+ * @param v the boolean to be written.
+ */
+ void writeBoolean(boolean v);
+
+ /**
+ * Writes to the output stream the eight low-order
+ * bits of the argument {@code v}.
+ * The 24 high-order bits of {@code v}
+ * are ignored. (This means that {@code writeByte}
+ * does exactly the same thing as {@code write}
+ * for an integer argument.) The byte written
+ * by this method may be read by the {@code readByte}
+ * method of interface {@code DataInput},
+ * which will then return a {@code byte}
+ * equal to {@code (byte)v}.
+ *
+ * @param v the byte value to be written.
+ */
+ void writeByte(int v);
+
+ /**
+ * Writes two bytes to the output
+ * stream to represent the value of the argument.
+ * The byte values to be written, in the order
+ * shown, are:
+ *
+ * The bytes written by this method may be
+ * read by the {@code readShort} method
+ * of interface {@code DataInput}, which
+ * will then return a {@code short} equal
+ * to {@code (short)v}.
+ *
+ * @param v the {@code short} value to be written.
+ */
+ void writeShort(int v);
+
+ /**
+ * Writes a {@code char} value, which
+ * is comprised of two bytes, to the
+ * output stream.
+ * The byte values to be written, in the order
+ * shown, are:
+ *
+ * The bytes written by this method may be
+ * read by the {@code readChar} method
+ * of interface {@code DataInput}, which
+ * will then return a {@code char} equal
+ * to {@code (char)v}.
+ *
+ * @param v the {@code char} value to be written.
+ */
+ void writeChar(int v);
+
+ /**
+ * Writes an {@code int} value, which is
+ * comprised of four bytes, to the output stream.
+ * The byte values to be written, in the order
+ * shown, are:
+ *
+ * The bytes written by this method may be read
+ * by the {@code readInt} method of interface
+ * {@code DataInput}, which will then
+ * return an {@code int} equal to {@code v}.
+ *
+ * @param v the {@code int} value to be written.
+ */
+ void writeInt(int v);
+
+ /**
+ * Writes a {@code long} value, which is
+ * comprised of eight bytes, to the output stream.
+ * The byte values to be written, in the order
+ * shown, are:
+ *
+ * The bytes written by this method may be
+ * read by the {@code readLong} method
+ * of interface {@code DataInput}, which
+ * will then return a {@code long} equal
+ * to {@code v}.
+ *
+ * @param v the {@code long} value to be written.
+ */
+ void writeLong(long v);
+
+ /**
+ * Writes a {@code float} value,
+ * which is comprised of four bytes, to the output stream.
+ * It does this as if it first converts this
+ * {@code float} value to an {@code int}
+ * in exactly the manner of the {@code Float.floatToIntBits}
+ * method and then writes the {@code int}
+ * value in exactly the manner of the {@code writeInt}
+ * method. The bytes written by this method
+ * may be read by the {@code readFloat}
+ * method of interface {@code DataInput},
+ * which will then return a {@code float}
+ * equal to {@code v}.
+ *
+ * @param v the {@code float} value to be written.
+ */
+ void writeFloat(float v);
+
+ /**
+ * Writes a {@code double} value,
+ * which is comprised of eight bytes, to the output stream.
+ * It does this as if it first converts this
+ * {@code double} value to a {@code long}
+ * in exactly the manner of the {@code Double.doubleToLongBits}
+ * method and then writes the {@code long}
+ * value in exactly the manner of the {@code writeLong}
+ * method. The bytes written by this method
+ * may be read by the {@code readDouble}
+ * method of interface {@code DataInput},
+ * which will then return a {@code double}
+ * equal to {@code v}.
+ *
+ * @param v the {@code double} value to be written.
+ */
+ void writeDouble(double v);
+
+ /**
+ * Writes a string to the output stream.
+ * For every character in the string
+ * {@code s}, taken in order, one byte
+ * is written to the output stream. If
+ * {@code s} is {@code null}, a {@code NullPointerException}
+ * is thrown. If {@code s.length}
+ * is zero, then no bytes are written. Otherwise,
+ * the character {@code s[0]} is written
+ * first, then {@code s[1]}, and so on;
+ * the last character written is {@code s[s.length-1]}.
+ * For each character, one byte is written,
+ * the low-order byte, in exactly the manner
+ * of the {@code writeByte} method . The
+ * high-order eight bits of each character
+ * in the string are ignored.
+ *
+ * @param s the string of bytes to be written.
+ */
+ void writeBytes(String s);
+
+ /**
+ * Writes every character in the string {@code s},
+ * to the output stream, in order,
+ * two bytes per character. If {@code s}
+ * is {@code null}, a {@code NullPointerException}
+ * is thrown. If {@code s.length}
+ * is zero, then no characters are written.
+ * Otherwise, the character {@code s[0]}
+ * is written first, then {@code s[1]},
+ * and so on; the last character written is
+ * {@code s[s.length-1]}. For each character,
+ * two bytes are actually written, high-order
+ * byte first, in exactly the manner of the
+ * {@code writeChar} method.
+ *
+ * @param s the string value to be written.
+ */
+ void writeChars(String s);
+
+ /**
+ * Writes two bytes of length information
+ * to the output stream, followed
+ * by the
+ * modified UTF-8
+ * representation
+ * of every character in the string {@code s}.
+ * If {@code s} is {@code null},
+ * a {@code NullPointerException} is thrown.
+ * Each character in the string {@code s}
+ * is converted to a group of one, two, or
+ * three bytes, depending on the value of the
+ * character.
+ * If a character {@code c}
+ * is in the range
+ * If a character {@code c} is If a character
+ * {@code c} is in the range First,
+ * the total number of bytes needed to represent
+ * all the characters of {@code s} is
+ * calculated. If this number is larger than
+ * {@code 65535}, then a {@code UTFDataFormatException}
+ * is thrown. Otherwise, this length is written
+ * to the output stream in exactly the manner
+ * of the {@code writeShort} method;
+ * after this, the one-, two-, or three-byte
+ * representation of each character in the
+ * string {@code s} is written. The
+ * bytes written by this method may be read
+ * by the {@code readUTF} method of interface
+ * {@code DataInput}, which will then
+ * return a {@code String} equal to {@code s}.
+ *
+ * @param s the string value to be written.
+ */
+ void writeUTF(String s);
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java
new file mode 100644
index 0000000..32cc8d5
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+package org.warp.commonutils.stream;
+
+import java.io.DataOutputStream;
+
+/**
+ * A data output stream lets an application write primitive Java data
+ * types to an output stream in a portable way. An application can
+ * then use a data input stream to read the data back in.
+ *
+ * @author unascribed
+ * @see java.io.DataInputStream
+ * @since 1.0
+ */
+public class SafeDataOutputStream extends SafeFilterOutputStream implements SafeDataOutput {
+ /**
+ * The number of bytes written to the data output stream so far.
+ * If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
+ */
+ protected int written;
+
+ /**
+ * bytearr is initialized on demand by writeUTF
+ */
+ private byte[] bytearr = null;
+
+ /**
+ * Creates a new data output stream to write data to the specified
+ * underlying output stream. The counter {@code written} is
+ * set to zero.
+ *
+ * @param out the underlying output stream, to be saved for later
+ * use.
+ * @see SafeFilterOutputStream#out
+ */
+ public SafeDataOutputStream(SafeOutputStream out) {
+ super(out);
+ }
+
+ /**
+ * Increases the written counter by the specified value
+ * until it reaches Integer.MAX_VALUE.
+ */
+ private void incCount(int value) {
+ int temp = written + value;
+ if (temp < 0) {
+ temp = Integer.MAX_VALUE;
+ }
+ written = temp;
+ }
+
+ /**
+ * Writes the specified byte (the low eight bits of the argument
+ * {@code b}) to the underlying output stream. If no exception
+ * is thrown, the counter {@code written} is incremented by
+ * {@code 1}.
+ *
+ * Implements the {@code write} method of {@code OutputStream}.
+ *
+ * @param b the {@code byte} to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public synchronized void write(int b) {
+ out.write(b);
+ incCount(1);
+ }
+
+ /**
+ * Writes {@code len} bytes from the specified byte array
+ * starting at offset {@code off} to the underlying output stream.
+ * If no exception is thrown, the counter {@code written} is
+ * incremented by {@code len}.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @see SafeFilterOutputStream#out
+ */
+ public synchronized void write(byte b[], int off, int len)
+ {
+ out.write(b, off, len);
+ incCount(len);
+ }
+
+ /**
+ * Flushes this data output stream. This forces any buffered output
+ * bytes to be written out to the stream.
+ *
+ * The {@code flush} method of {@code SafeDataOutputStream}
+ * calls the {@code flush} method of its underlying output stream.
+ *
+ * @see SafeFilterOutputStream#out
+ * @see java.io.OutputStream#flush()
+ */
+ public void flush() {
+ out.flush();
+ }
+
+ /**
+ * Writes a {@code boolean} to the underlying output stream as
+ * a 1-byte value. The value {@code true} is written out as the
+ * value {@code (byte)1}; the value {@code false} is
+ * written out as the value {@code (byte)0}. If no exception is
+ * thrown, the counter {@code written} is incremented by
+ * {@code 1}.
+ *
+ * @param v a {@code boolean} value to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeBoolean(boolean v) {
+ out.write(v ? 1 : 0);
+ incCount(1);
+ }
+
+ /**
+ * Writes out a {@code byte} to the underlying output stream as
+ * a 1-byte value. If no exception is thrown, the counter
+ * {@code written} is incremented by {@code 1}.
+ *
+ * @param v a {@code byte} value to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeByte(int v) {
+ out.write(v);
+ incCount(1);
+ }
+
+ /**
+ * Writes a {@code short} to the underlying output stream as two
+ * bytes, high byte first. If no exception is thrown, the counter
+ * {@code written} is incremented by {@code 2}.
+ *
+ * @param v a {@code short} to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeShort(int v) {
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ incCount(2);
+ }
+
+ /**
+ * Writes a {@code char} to the underlying output stream as a
+ * 2-byte value, high byte first. If no exception is thrown, the
+ * counter {@code written} is incremented by {@code 2}.
+ *
+ * @param v a {@code char} value to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeChar(int v) {
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ incCount(2);
+ }
+
+ /**
+ * Writes an {@code int} to the underlying output stream as four
+ * bytes, high byte first. If no exception is thrown, the counter
+ * {@code written} is incremented by {@code 4}.
+ *
+ * @param v an {@code int} to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeInt(int v) {
+ out.write((v >>> 24) & 0xFF);
+ out.write((v >>> 16) & 0xFF);
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ incCount(4);
+ }
+
+ private byte writeBuffer[] = new byte[8];
+
+ /**
+ * Writes a {@code long} to the underlying output stream as eight
+ * bytes, high byte first. In no exception is thrown, the counter
+ * {@code written} is incremented by {@code 8}.
+ *
+ * @param v a {@code long} to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeLong(long v) {
+ writeBuffer[0] = (byte)(v >>> 56);
+ writeBuffer[1] = (byte)(v >>> 48);
+ writeBuffer[2] = (byte)(v >>> 40);
+ writeBuffer[3] = (byte)(v >>> 32);
+ writeBuffer[4] = (byte)(v >>> 24);
+ writeBuffer[5] = (byte)(v >>> 16);
+ writeBuffer[6] = (byte)(v >>> 8);
+ writeBuffer[7] = (byte)(v >>> 0);
+ out.write(writeBuffer, 0, 8);
+ incCount(8);
+ }
+
+ /**
+ * Converts the float argument to an {@code int} using the
+ * {@code floatToIntBits} method in class {@code Float},
+ * and then writes that {@code int} value to the underlying
+ * output stream as a 4-byte quantity, high byte first. If no
+ * exception is thrown, the counter {@code written} is
+ * incremented by {@code 4}.
+ *
+ * @param v a {@code float} value to be written.
+ * @see SafeFilterOutputStream#out
+ * @see java.lang.Float#floatToIntBits(float)
+ */
+ public final void writeFloat(float v) {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ /**
+ * Converts the double argument to a {@code long} using the
+ * {@code doubleToLongBits} method in class {@code Double},
+ * and then writes that {@code long} value to the underlying
+ * output stream as an 8-byte quantity, high byte first. If no
+ * exception is thrown, the counter {@code written} is
+ * incremented by {@code 8}.
+ *
+ * @param v a {@code double} value to be written.
+ * @see SafeFilterOutputStream#out
+ * @see java.lang.Double#doubleToLongBits(double)
+ */
+ public final void writeDouble(double v) {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ /**
+ * Writes out the string to the underlying output stream as a
+ * sequence of bytes. Each character in the string is written out, in
+ * sequence, by discarding its high eight bits. If no exception is
+ * thrown, the counter {@code written} is incremented by the
+ * length of {@code s}.
+ *
+ * @param s a string of bytes to be written.
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeBytes(String s) {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++) {
+ out.write((byte)s.charAt(i));
+ }
+ incCount(len);
+ }
+
+ /**
+ * Writes a string to the underlying output stream as a sequence of
+ * characters. Each character is written to the data output stream as
+ * if by the {@code writeChar} method. If no exception is
+ * thrown, the counter {@code written} is incremented by twice
+ * the length of {@code s}.
+ *
+ * @param s a {@code String} value to be written.
+ * @see SafeDataOutputStream#writeChar(int)
+ * @see SafeFilterOutputStream#out
+ */
+ public final void writeChars(String s) {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++) {
+ int v = s.charAt(i);
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ }
+ incCount(len * 2);
+ }
+
+ /**
+ * Writes a string to the underlying output stream using
+ * modified UTF-8
+ * encoding in a machine-independent manner.
+ *
+ * First, two bytes are written to the output stream as if by the
+ * {@code writeShort} method giving the number of bytes to
+ * follow. This value is the number of bytes actually written out,
+ * not the length of the string. Following the length, each character
+ * of the string is output, in sequence, using the modified UTF-8 encoding
+ * for the character. If no exception is thrown, the counter
+ * {@code written} is incremented by the total number of
+ * bytes written to the output stream. This will be at least two
+ * plus the length of {@code str}, and at most two plus
+ * thrice the length of {@code str}.
+ *
+ * @param str a string to be written.
+ * @see #writeChars(String)
+ */
+ public final void writeUTF(String str) {
+ writeUTF(str, this);
+ }
+
+ /**
+ * Writes a string to the specified DataOutput using
+ * modified UTF-8
+ * encoding in a machine-independent manner.
+ *
+ * First, two bytes are written to out as if by the {@code writeShort}
+ * method giving the number of bytes to follow. This value is the number of
+ * bytes actually written out, not the length of the string. Following the
+ * length, each character of the string is output, in sequence, using the
+ * modified UTF-8 encoding for the character. If no exception is thrown, the
+ * counter {@code written} is incremented by the total number of
+ * bytes written to the output stream. This will be at least two
+ * plus the length of {@code str}, and at most two plus
+ * thrice the length of {@code str}.
+ *
+ * @param str a string to be written.
+ * @param out destination to write to
+ * @return The number of bytes written out.
+ */
+ static int writeUTF(String str, SafeDataOutput out) {
+ final int strlen = str.length();
+ int utflen = strlen; // optimized for ASCII
+
+ for (int i = 0; i < strlen; i++) {
+ int c = str.charAt(i);
+ if (c >= 0x80 || c == 0)
+ utflen += (c >= 0x800) ? 2 : 1;
+ }
+
+ if (utflen > 65535 || /* overflow */ utflen < strlen)
+ throw new IllegalArgumentException(tooLongMsg(str, utflen));
+
+ final byte[] bytearr;
+ if (out instanceof SafeDataOutputStream) {
+ SafeDataOutputStream dos = (SafeDataOutputStream)out;
+ if (dos.bytearr == null || (dos.bytearr.length < (utflen + 2)))
+ dos.bytearr = new byte[(utflen*2) + 2];
+ bytearr = dos.bytearr;
+ } else {
+ bytearr = new byte[utflen + 2];
+ }
+
+ int count = 0;
+ bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
+ bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
+
+ int i = 0;
+ for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII
+ int c = str.charAt(i);
+ if (c >= 0x80 || c == 0) break;
+ bytearr[count++] = (byte) c;
+ }
+
+ for (; i < strlen; i++) {
+ int c = str.charAt(i);
+ if (c < 0x80 && c != 0) {
+ bytearr[count++] = (byte) c;
+ } else if (c >= 0x800) {
+ bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+ bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
+ bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
+ } else {
+ bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
+ bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
+ }
+ }
+ out.write(bytearr, 0, utflen + 2);
+ return utflen + 2;
+ }
+
+ private static String tooLongMsg(String s, int bits32) {
+ int slen = s.length();
+ String head = s.substring(0, 8);
+ String tail = s.substring(slen - 8, slen);
+ // handle int overflow with max 3x expansion
+ long actualLength = (long)slen + Integer.toUnsignedLong(bits32 - slen);
+ return "encoded string (" + head + "..." + tail + ") too long: "
+ + actualLength + " bytes";
+ }
+
+ /**
+ * Returns the current value of the counter {@code written},
+ * the number of bytes written to this data output stream so far.
+ * If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
+ *
+ * @return the value of the {@code written} field.
+ * @see SafeDataOutputStream#written
+ */
+ public final int size() {
+ return written;
+ }
+
+ public DataOutputStream asDataOutputStream() {
+ return new DataOutputStream(this.out);
+ }
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafeFilterInputStream.java b/src/main/java/org/warp/commonutils/stream/SafeFilterInputStream.java
new file mode 100644
index 0000000..28be7e9
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafeFilterInputStream.java
@@ -0,0 +1,210 @@
+package org.warp.commonutils.stream;
+
+/**
+ * A {@code FilterInputStream} contains
+ * some other input stream, which it uses as
+ * its basic source of data, possibly transforming
+ * the data along the way or providing additional
+ * functionality. The class {@code FilterInputStream}
+ * itself simply overrides all methods of
+ * {@code InputStream} with versions that
+ * pass all requests to the contained input
+ * stream. Subclasses of {@code FilterInputStream}
+ * may further override some of these methods
+ * and may also provide additional methods
+ * and fields.
+ *
+ * @author Jonathan Payne
+ * @since 1.0
+ */
+public class SafeFilterInputStream extends SafeInputStream {
+ /**
+ * The input stream to be filtered.
+ */
+ protected volatile SafeInputStream in;
+
+ /**
+ * Creates a {@code FilterInputStream}
+ * by assigning the argument {@code in}
+ * to the field {@code this.in} so as
+ * to remember it for later use.
+ *
+ * @param in the underlying input stream, or {@code null} if
+ * this instance is to be created without an underlying stream.
+ */
+ protected SafeFilterInputStream(SafeInputStream in) {
+ this.in = in;
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an {@code int} in the range
+ * {@code 0} to {@code 255}. If no byte is available
+ * because the end of the stream has been reached, the value
+ * {@code -1} is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ *
+ * This method
+ * simply performs {@code in.read()} and returns the result.
+ *
+ * @return the next byte of data, or {@code -1} if the end of the
+ * stream is reached.
+ * @see SafeFilterInputStream#in
+ */
+ public int read() {
+ return in.read();
+ }
+
+ /**
+ * Reads up to {@code b.length} bytes of data from this
+ * input stream into an array of bytes. This method blocks until some
+ * input is available.
+ *
+ * This method simply performs the call
+ * {@code read(b, 0, b.length)} and returns
+ * the result. It is important that it does
+ * not do {@code in.read(b)} instead;
+ * certain subclasses of {@code FilterInputStream}
+ * depend on the implementation strategy actually
+ * used.
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * {@code -1} if there is no more data because the end of
+ * the stream has been reached.
+ * @see SafeFilterInputStream#read(byte[], int, int)
+ */
+ public int read(byte b[]) {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Reads up to {@code len} bytes of data from this input stream
+ * into an array of bytes. If {@code len} is not zero, the method
+ * blocks until some input is available; otherwise, no
+ * bytes are read and {@code 0} is returned.
+ *
+ * This method simply performs {@code in.read(b, off, len)}
+ * and returns the result.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array {@code b}
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * {@code -1} if there is no more data because the end of
+ * the stream has been reached.
+ * @throws NullPointerException If {@code b} is {@code null}.
+ * @throws IndexOutOfBoundsException If {@code off} is negative,
+ * {@code len} is negative, or {@code len} is greater than
+ * {@code b.length - off}
+ * @see SafeFilterInputStream#in
+ */
+ public int read(byte b[], int off, int len) {
+ return in.read(b, off, len);
+ }
+
+ /**
+ * Skips over and discards {@code n} bytes of data from the
+ * input stream. The {@code skip} method may, for a variety of
+ * reasons, end up skipping over some smaller number of bytes,
+ * possibly {@code 0}. The actual number of bytes skipped is
+ * returned.
+ *
+ * This method simply performs {@code in.skip(n)}.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ */
+ public long skip(long n) {
+ return in.skip(n);
+ }
+
+ /**
+ * Returns an estimate of the number of bytes that can be read (or
+ * skipped over) from this input stream without blocking by the next
+ * caller of a method for this input stream. The next caller might be
+ * the same thread or another thread. A single read or skip of this
+ * many bytes will not block, but may read or skip fewer bytes.
+ *
+ * This method returns the result of {@link #in in}.available().
+ *
+ * @return an estimate of the number of bytes that can be read (or skipped
+ * over) from this input stream without blocking.
+ */
+ public int available() {
+ return in.available();
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * This
+ * method simply performs {@code in.close()}.
+ *
+ * @see SafeFilterInputStream#in
+ */
+ public void close() {
+ in.close();
+ }
+
+ /**
+ * Marks the current position in this input stream. A subsequent
+ * call to the {@code reset} method repositions this stream at
+ * the last marked position so that subsequent reads re-read the same bytes.
+ *
+ * The {@code readlimit} argument tells this input stream to
+ * allow that many bytes to be read before the mark position gets
+ * invalidated.
+ *
+ * This method simply performs {@code in.mark(readlimit)}.
+ *
+ * @param readlimit the maximum limit of bytes that can be read before
+ * the mark position becomes invalid.
+ * @see SafeFilterInputStream#in
+ * @see SafeFilterInputStream#reset()
+ */
+ public synchronized void mark(int readlimit) {
+ in.mark(readlimit);
+ }
+
+ /**
+ * Repositions this stream to the position at the time the
+ * {@code mark} method was last called on this input stream.
+ *
+ * This method
+ * simply performs {@code in.reset()}.
+ *
+ * Stream marks are intended to be used in
+ * situations where you need to read ahead a little to see what's in
+ * the stream. Often this is most easily done by invoking some
+ * general parser. If the stream is of the type handled by the
+ * parse, it just chugs along happily. If the stream is not of
+ * that type, the parser should toss an exception when it fails.
+ * If this happens within readlimit bytes, it allows the outer
+ * code to reset the stream and try another parser.
+ *
+ * @see SafeFilterInputStream#in
+ * @see SafeFilterInputStream#mark(int)
+ */
+ public synchronized void reset() {
+ in.reset();
+ }
+
+ /**
+ * Tests if this input stream supports the {@code mark}
+ * and {@code reset} methods.
+ * This method
+ * simply performs {@code in.markSupported()}.
+ *
+ * @return {@code true} if this stream type supports the
+ * {@code mark} and {@code reset} method;
+ * {@code false} otherwise.
+ * @see SafeFilterInputStream#in
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.InputStream#reset()
+ */
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafeFilterOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeFilterOutputStream.java
new file mode 100644
index 0000000..f4fd0e5
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafeFilterOutputStream.java
@@ -0,0 +1,180 @@
+package org.warp.commonutils.stream;
+
+
+/**
+ * This class is the superclass of all classes that filter output
+ * streams. These streams sit on top of an already existing output
+ * stream (the underlying output stream) which it uses as its
+ * basic sink of data, but possibly transforming the data along the
+ * way or providing additional functionality.
+ *
+ * The class {@code FilterOutputStream} itself simply overrides
+ * all methods of {@code SafeOutputStream} with versions that pass
+ * all requests to the underlying output stream. Subclasses of
+ * {@code FilterOutputStream} may further override some of these
+ * methods as well as provide additional methods and fields.
+ *
+ * @author Jonathan Payne
+ * @since 1.0
+ */
+public class SafeFilterOutputStream extends SafeOutputStream {
+ /**
+ * The underlying output stream to be filtered.
+ */
+ protected SafeOutputStream out;
+
+ /**
+ * Whether the stream is closed; implicitly initialized to false.
+ */
+ private volatile boolean closed;
+
+ /**
+ * Object used to prevent a race on the 'closed' instance variable.
+ */
+ private final Object closeLock = new Object();
+
+ /**
+ * Creates an output stream filter built on top of the specified
+ * underlying output stream.
+ *
+ * @param out the underlying output stream to be assigned to
+ * the field {@code this.out} for later use, or
+ * {@code null} if this instance is to be
+ * created without an underlying stream.
+ */
+ public SafeFilterOutputStream(SafeOutputStream out) {
+ this.out = out;
+ }
+
+ /**
+ * Writes the specified {@code byte} to this output stream.
+ *
+ * The {@code write} method of {@code FilterOutputStream}
+ * calls the {@code write} method of its underlying output stream,
+ * that is, it performs {@code out.write(b)}.
+ *
+ * Implements the abstract {@code write} method of {@code SafeOutputStream}.
+ *
+ * @param b the {@code byte}.
+ */
+ @Override
+ public void write(int b) {
+ out.write(b);
+ }
+
+ /**
+ * Writes {@code b.length} bytes to this output stream.
+ *
+ * The {@code write} method of {@code FilterOutputStream}
+ * calls its {@code write} method of three arguments with the
+ * arguments {@code b}, {@code 0}, and
+ * {@code b.length}.
+ *
+ * Note that this method does not call the one-argument
+ * {@code write} method of its underlying output stream with
+ * the single argument {@code b}.
+ *
+ * @param b the data to be written.
+ * @see SafeFilterOutputStream#write(byte[], int, int)
+ */
+ @Override
+ public void write(byte b[]) {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes {@code len} bytes from the specified
+ * {@code byte} array starting at offset {@code off} to
+ * this output stream.
+ *
+ * The {@code write} method of {@code FilterOutputStream}
+ * calls the {@code write} method of one argument on each
+ * {@code byte} to output.
+ *
+ * Note that this method does not call the {@code write} method
+ * of its underlying output stream with the same arguments. Subclasses
+ * of {@code FilterOutputStream} should provide a more efficient
+ * implementation of this method.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @see SafeFilterOutputStream#write(int)
+ */
+ @Override
+ public void write(byte b[], int off, int len) {
+ if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
+ throw new IndexOutOfBoundsException();
+
+ for (int i = 0 ; i < len ; i++) {
+ write(b[off + i]);
+ }
+ }
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out to the stream.
+ *
+ * The {@code flush} method of {@code FilterOutputStream}
+ * calls the {@code flush} method of its underlying output stream.
+ *
+ * @see SafeFilterOutputStream#out
+ */
+ @Override
+ public void flush() {
+ out.flush();
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with the stream.
+ *
+ * When not already closed, the {@code close} method of {@code
+ * FilterOutputStream} calls its {@code flush} method, and then
+ * calls the {@code close} method of its underlying output stream.
+ *
+ * @see SafeFilterOutputStream#flush()
+ * @see SafeFilterOutputStream#out
+ */
+ @Override
+ public void close() {
+ if (closed) {
+ return;
+ }
+ synchronized (closeLock) {
+ if (closed) {
+ return;
+ }
+ closed = true;
+ }
+
+ Throwable flushException = null;
+ try {
+ flush();
+ } catch (Throwable e) {
+ flushException = e;
+ throw e;
+ } finally {
+ if (flushException == null) {
+ out.close();
+ } else {
+ try {
+ out.close();
+ } catch (Throwable closeException) {
+ // evaluate possible precedence of flushException over closeException
+ if ((flushException instanceof ThreadDeath) &&
+ !(closeException instanceof ThreadDeath)) {
+ flushException.addSuppressed(closeException);
+ throw (ThreadDeath) flushException;
+ }
+
+ if (flushException != closeException) {
+ closeException.addSuppressed(flushException);
+ }
+
+ throw closeException;
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafeInputStream.java b/src/main/java/org/warp/commonutils/stream/SafeInputStream.java
new file mode 100644
index 0000000..db60727
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafeInputStream.java
@@ -0,0 +1,201 @@
+package org.warp.commonutils.stream;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public abstract class SafeInputStream extends InputStream {
+
+ // MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
+ // use when skipping.
+ private static final int MAX_SKIP_BUFFER_SIZE = 2048;
+
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ @Override
+ public abstract int read();
+
+ public int read(byte b[]) {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte b[], int off, int len) {
+ Objects.checkFromIndexSize(off, len, b.length);
+ if (len == 0) {
+ return 0;
+ }
+
+ int c = read();
+ if (c == -1) {
+ return -1;
+ }
+ b[off] = (byte)c;
+
+ int i = 1;
+ for (; i < len ; i++) {
+ c = read();
+ if (c == -1) {
+ break;
+ }
+ b[off + i] = (byte)c;
+ }
+ return i;
+ }
+
+ public byte[] readAllBytes() {
+ return readNBytes(Integer.MAX_VALUE);
+ }
+
+ private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+ public byte[] readNBytes(int len) {
+ if (len < 0) {
+ throw new IllegalArgumentException("len < 0");
+ }
+
+ List This class has two methods, both specified as optional. This apparently bizarre
+ * behaviour is necessary because of wrapper classes which use reflection
+ * to support those methods (see, e.g., {@link MeasurableInputStream}, {@link FastBufferedInputStream} and {@link FastBufferedOutputStream}).
+ *
+ * @since 6.0.0
+ */
+
+public interface SafeMeasurableStream {
+
+ /** Returns the overall length of this stream (optional operation). In most cases, this will require the
+ * stream to perform some extra action, possibly changing the state of the input stream itself (typically, reading
+ * all the bytes up to the end, or flushing on output stream).
+ * Implementing classes should always document what state will the input stream be in
+ * after calling this method, and which kind of exception could be thrown.
+ */
+ long length();
+
+ /** Returns the current position in this stream (optional operation).
+ *
+ * Usually, the position is just the number of bytes read or written
+ * since the stream was opened, but in the case of a
+ * {@link it.unimi.dsi.fastutil.io.RepositionableStream} it
+ * represent the current position.
+ */
+ long position();
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafeOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeOutputStream.java
new file mode 100644
index 0000000..f0190d1
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafeOutputStream.java
@@ -0,0 +1,168 @@
+package org.warp.commonutils.stream;
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.OutputStream;
+import java.util.Objects;
+
+/**
+ * This abstract class is the superclass of all classes representing
+ * an output stream of bytes. An output stream accepts output bytes
+ * and sends them to some sink.
+ *
+ * Applications that need to define a subclass of
+ * {@code OutputStream} must always provide at least a method
+ * that writes one byte of output.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.BufferedOutputStream
+ * @see java.io.ByteArrayOutputStream
+ * @see java.io.DataOutputStream
+ * @see java.io.FilterOutputStream
+ * @see java.io.InputStream
+ * @see java.io.OutputStream#write(int)
+ * @since 1.0
+ */
+public abstract class SafeOutputStream extends OutputStream implements Closeable, Flushable {
+ /**
+ * Constructor for subclasses to call.
+ */
+ public SafeOutputStream() {}
+
+ /**
+ * Returns a new {@code OutputStream} which discards all bytes. The
+ * returned stream is initially open. The stream is closed by calling
+ * the {@code close()} method. Subsequent calls to {@code close()} have
+ * no effect.
+ *
+ * While the stream is open, the {@code write(int)}, {@code
+ * write(byte[])}, and {@code write(byte[], int, int)} methods do nothing.
+ * After the stream has been closed, these methods all throw {@code
+ * IOException}.
+ *
+ * The {@code flush()} method does nothing.
+ *
+ * @return an {@code OutputStream} which discards all bytes
+ *
+ * @since 11
+ */
+ public static java.io.OutputStream nullOutputStream() {
+ return new java.io.OutputStream() {
+ private volatile boolean closed;
+
+ private void ensureOpen() {
+ if (closed) {
+ throw new IllegalStateException("Stream closed");
+ }
+ }
+
+ @Override
+ public void write(int b) {
+ ensureOpen();
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) {
+ Objects.checkFromIndexSize(off, len, b.length);
+ ensureOpen();
+ }
+
+ @Override
+ public void close() {
+ closed = true;
+ }
+ };
+ }
+
+ /**
+ * Writes the specified byte to this output stream. The general
+ * contract for {@code write} is that one byte is written
+ * to the output stream. The byte to be written is the eight
+ * low-order bits of the argument {@code b}. The 24
+ * high-order bits of {@code b} are ignored.
+ *
+ * Subclasses of {@code OutputStream} must provide an
+ * implementation for this method.
+ *
+ * @param b the {@code byte}.
+ */
+ public abstract void write(int b);
+
+ /**
+ * Writes {@code b.length} bytes from the specified byte array
+ * to this output stream. The general contract for {@code write(b)}
+ * is that it should have exactly the same effect as the call
+ * {@code write(b, 0, b.length)}.
+ *
+ * @param b the data.
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ public void write(byte b[]) {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes {@code len} bytes from the specified byte array
+ * starting at offset {@code off} to this output stream.
+ * The general contract for {@code write(b, off, len)} is that
+ * some of the bytes in the array {@code b} are written to the
+ * output stream in order; element {@code b[off]} is the first
+ * byte written and {@code b[off+len-1]} is the last byte written
+ * by this operation.
+ *
+ * The {@code write} method of {@code OutputStream} calls
+ * the write method of one argument on each of the bytes to be
+ * written out. Subclasses are encouraged to override this method and
+ * provide a more efficient implementation.
+ *
+ * If {@code b} is {@code null}, a
+ * {@code NullPointerException} is thrown.
+ *
+ * If {@code off} is negative, or {@code len} is negative, or
+ * {@code off+len} is greater than the length of the array
+ * {@code b}, then an {@code IndexOutOfBoundsException} is thrown.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ */
+ public void write(byte b[], int off, int len) {
+ Objects.checkFromIndexSize(off, len, b.length);
+ // len == 0 condition implicitly handled by loop bounds
+ for (int i = 0 ; i < len ; i++) {
+ write(b[off + i]);
+ }
+ }
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out. The general contract of {@code flush} is
+ * that calling it is an indication that, if any bytes previously
+ * written have been buffered by the implementation of the output
+ * stream, such bytes should immediately be written to their
+ * intended destination.
+ *
+ * If the intended destination of this stream is an abstraction provided by
+ * the underlying operating system, for example a file, then flushing the
+ * stream guarantees only that bytes previously written to the stream are
+ * passed to the operating system for writing; it does not guarantee that
+ * they are actually written to a physical device such as a disk drive.
+ *
+ * The {@code flush} method of {@code OutputStream} does nothing.
+ *
+ */
+ public void flush() {
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with this stream. The general contract of {@code close}
+ * is that it closes the output stream. A closed stream cannot perform
+ * output operations and cannot be reopened.
+ *
+ * The {@code close} method of {@code OutputStream} does nothing.
+ *
+ */
+ public void close() {
+ }
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafePushbackInputStream.java b/src/main/java/org/warp/commonutils/stream/SafePushbackInputStream.java
new file mode 100644
index 0000000..04420d9
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafePushbackInputStream.java
@@ -0,0 +1,332 @@
+package org.warp.commonutils.stream;
+
+/**
+ * A {@code PushbackInputStream} adds
+ * functionality to another input stream, namely
+ * the ability to "push back" or "unread" bytes,
+ * by storing pushed-back bytes in an internal buffer.
+ * This is useful in situations where
+ * it is convenient for a fragment of code
+ * to read an indefinite number of data bytes
+ * that are delimited by a particular byte
+ * value; after reading the terminating byte,
+ * the code fragment can "unread" it, so that
+ * the next read operation on the input stream
+ * will reread the byte that was pushed back.
+ * For example, bytes representing the characters
+ * constituting an identifier might be terminated
+ * by a byte representing an operator character;
+ * a method whose job is to read just an identifier
+ * can read until it sees the operator and
+ * then push the operator back to be re-read.
+ *
+ * @author David Connelly
+ * @author Jonathan Payne
+ * @since 1.0
+ */
+public class SafePushbackInputStream extends SafeFilterInputStream {
+ /**
+ * The pushback buffer.
+ * @since 1.1
+ */
+ protected byte[] buf;
+
+ /**
+ * The position within the pushback buffer from which the next byte will
+ * be read. When the buffer is empty, {@code pos} is equal to
+ * {@code buf.length}; when the buffer is full, {@code pos} is
+ * equal to zero.
+ *
+ * @since 1.1
+ */
+ protected int pos;
+
+ /**
+ * Check to make sure that this stream has not been closed
+ */
+ private void ensureOpen() {
+ if (in == null)
+ throw new IllegalStateException("Stream closed");
+ }
+
+ /**
+ * Creates a {@code PushbackInputStream}
+ * with a pushback buffer of the specified {@code size},
+ * and saves its argument, the input stream
+ * {@code in}, for later use. Initially,
+ * the pushback buffer is empty.
+ *
+ * @param in the input stream from which bytes will be read.
+ * @param size the size of the pushback buffer.
+ * @throws IllegalArgumentException if {@code size <= 0}
+ * @since 1.1
+ */
+ public SafePushbackInputStream(SafeInputStream in, int size) {
+ super(in);
+ if (size <= 0) {
+ throw new IllegalArgumentException("size <= 0");
+ }
+ this.buf = new byte[size];
+ this.pos = size;
+ }
+
+ /**
+ * Creates a {@code PushbackInputStream}
+ * with a 1-byte pushback buffer, and saves its argument, the input stream
+ * {@code in}, for later use. Initially,
+ * the pushback buffer is empty.
+ *
+ * @param in the input stream from which bytes will be read.
+ */
+ public SafePushbackInputStream(SafeInputStream in) {
+ this(in, 1);
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an {@code int} in the range
+ * {@code 0} to {@code 255}. If no byte is available
+ * because the end of the stream has been reached, the value
+ * {@code -1} is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ *
+ * This method returns the most recently pushed-back byte, if there is
+ * one, and otherwise calls the {@code read} method of its underlying
+ * input stream and returns whatever value that method returns.
+ *
+ * @return the next byte of data, or {@code -1} if the end of the
+ * stream has been reached.
+ * or an I/O error occurs.
+ * @see java.io.InputStream#read()
+ */
+ public int read() {
+ ensureOpen();
+ if (pos < buf.length) {
+ return buf[pos++] & 0xff;
+ }
+ return super.read();
+ }
+
+ /**
+ * Reads up to {@code len} bytes of data from this input stream into
+ * an array of bytes. This method first reads any pushed-back bytes; after
+ * that, if fewer than {@code len} bytes have been read then it
+ * reads from the underlying input stream. If {@code len} is not zero, the method
+ * blocks until at least 1 byte of input is available; otherwise, no
+ * bytes are read and {@code 0} is returned.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array {@code b}
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * {@code -1} if there is no more data because the end of
+ * the stream has been reached.
+ * @throws NullPointerException If {@code b} is {@code null}.
+ * @throws IndexOutOfBoundsException If {@code off} is negative,
+ * {@code len} is negative, or {@code len} is greater than
+ * {@code b.length - off}
+ * or an I/O error occurs.
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ public int read(byte[] b, int off, int len) {
+ ensureOpen();
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int avail = buf.length - pos;
+ if (avail > 0) {
+ if (len < avail) {
+ avail = len;
+ }
+ System.arraycopy(buf, pos, b, off, avail);
+ pos += avail;
+ off += avail;
+ len -= avail;
+ }
+ if (len > 0) {
+ len = super.read(b, off, len);
+ if (len == -1) {
+ return avail == 0 ? -1 : avail;
+ }
+ return avail + len;
+ }
+ return avail;
+ }
+
+ /**
+ * Pushes back a byte by copying it to the front of the pushback buffer.
+ * After this method returns, the next byte to be read will have the value
+ * {@code (byte)b}.
+ *
+ * @param b the {@code int} value whose low-order
+ * byte is to be pushed back.
+ */
+ public void unread(int b) {
+ ensureOpen();
+ if (pos == 0) {
+ throw new IllegalStateException("Push back buffer is full");
+ }
+ buf[--pos] = (byte)b;
+ }
+
+ /**
+ * Pushes back a portion of an array of bytes by copying it to the front
+ * of the pushback buffer. After this method returns, the next byte to be
+ * read will have the value {@code b[off]}, the byte after that will
+ * have the value {@code b[off+1]}, and so forth.
+ *
+ * @param b the byte array to push back.
+ * @param off the start offset of the data.
+ * @param len the number of bytes to push back.
+ * @throws NullPointerException If {@code b} is {@code null}.
+ * @since 1.1
+ */
+ public void unread(byte[] b, int off, int len) {
+ ensureOpen();
+ if (len > pos) {
+ throw new IllegalStateException("Push back buffer is full");
+ }
+ pos -= len;
+ System.arraycopy(b, off, buf, pos, len);
+ }
+
+ /**
+ * Pushes back an array of bytes by copying it to the front of the
+ * pushback buffer. After this method returns, the next byte to be read
+ * will have the value {@code b[0]}, the byte after that will have the
+ * value {@code b[1]}, and so forth.
+ *
+ * @param b the byte array to push back
+ * @throws NullPointerException If {@code b} is {@code null}.
+ * @since 1.1
+ */
+ public void unread(byte[] b) {
+ unread(b, 0, b.length);
+ }
+
+ /**
+ * Returns an estimate of the number of bytes that can be read (or
+ * skipped over) from this input stream without blocking by the next
+ * invocation of a method for this input stream. The next invocation might be
+ * the same thread or another thread. A single read or skip of this
+ * many bytes will not block, but may read or skip fewer bytes.
+ *
+ * The method returns the sum of the number of bytes that have been
+ * pushed back and the value returned by {@link
+ * SafeFilterInputStream#available available}.
+ *
+ * @return the number of bytes that can be read (or skipped over) from
+ * the input stream without blocking.
+ * @see SafeFilterInputStream#in
+ * @see java.io.InputStream#available()
+ */
+ public int available() {
+ ensureOpen();
+ int n = buf.length - pos;
+ int avail = super.available();
+ return n > (Integer.MAX_VALUE - avail)
+ ? Integer.MAX_VALUE
+ : n + avail;
+ }
+
+ /**
+ * Skips over and discards {@code n} bytes of data from this
+ * input stream. The {@code skip} method may, for a variety of
+ * reasons, end up skipping over some smaller number of bytes,
+ * possibly zero. If {@code n} is negative, no bytes are skipped.
+ *
+ * The {@code skip} method of {@code PushbackInputStream}
+ * first skips over the bytes in the pushback buffer, if any. It then
+ * calls the {@code skip} method of the underlying input stream if
+ * more bytes need to be skipped. The actual number of bytes skipped
+ * is returned.
+ *
+ * @param n {@inheritDoc}
+ * @return {@inheritDoc}
+ * @see SafeFilterInputStream#in
+ * @see java.io.InputStream#skip(long n)
+ * @since 1.2
+ */
+ public long skip(long n) {
+ ensureOpen();
+ if (n <= 0) {
+ return 0;
+ }
+
+ long pskip = buf.length - pos;
+ if (pskip > 0) {
+ if (n < pskip) {
+ pskip = n;
+ }
+ pos += pskip;
+ n -= pskip;
+ }
+ if (n > 0) {
+ pskip += super.skip(n);
+ }
+ return pskip;
+ }
+
+ /**
+ * Tests if this input stream supports the {@code mark} and
+ * {@code reset} methods, which it does not.
+ *
+ * @return {@code false}, since this class does not support the
+ * {@code mark} and {@code reset} methods.
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.InputStream#reset()
+ */
+ public boolean markSupported() {
+ return false;
+ }
+
+ /**
+ * Marks the current position in this input stream.
+ *
+ * The {@code mark} method of {@code PushbackInputStream}
+ * does nothing.
+ *
+ * @param readlimit the maximum limit of bytes that can be read before
+ * the mark position becomes invalid.
+ * @see java.io.InputStream#reset()
+ */
+ public synchronized void mark(int readlimit) {
+ }
+
+ /**
+ * Repositions this stream to the position at the time the
+ * {@code mark} method was last called on this input stream.
+ *
+ * The method {@code reset} for class
+ * {@code PushbackInputStream} does nothing except throw an
+ * {@code IOException}.
+ *
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.IOException
+ */
+ public synchronized void reset() {
+ throw new UnsupportedOperationException("mark/reset not supported");
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * Once the stream has been closed, further read(), unread(),
+ * available(), reset(), or skip() invocations will throw an IOException.
+ * Closing a previously closed stream has no effect.
+ *
+ */
+ public synchronized void close() {
+ if (in == null)
+ return;
+ in.close();
+ in = null;
+ buf = null;
+ }
+}
diff --git a/src/main/java/org/warp/commonutils/stream/SafeRepositionableStream.java b/src/main/java/org/warp/commonutils/stream/SafeRepositionableStream.java
new file mode 100644
index 0000000..e79f2df
--- /dev/null
+++ b/src/main/java/org/warp/commonutils/stream/SafeRepositionableStream.java
@@ -0,0 +1,40 @@
+package org.warp.commonutils.stream;
+
+/*
+ * Copyright (C) 2005-2020 Sebastiano Vigna
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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.
+ */
+
+
+/** A basic interface specifying positioning methods for a byte stream.
+ *
+ * @author Sebastiano Vigna
+ * @since 4.4
+ */
+
+public interface SafeRepositionableStream {
+
+ /** Sets the current stream position.
+ *
+ * @param newPosition the new stream position.
+ */
+ void position(long newPosition);
+
+ /** Returns the current stream position.
+ *
+ * @return the current stream position.
+ */
+ long position();
+
+}
+ * with:
+ *
+ * DataInputStream d = new DataInputStream(in);
+ *
+ *
+ * @return the next line of text from this input stream.
+ * @see java.io.BufferedReader#readLine()
+ * @see SafeFilterInputStream#in
+ */
+ @Deprecated
+ public final String readLine() {
+ char buf[] = lineBuffer;
+
+ if (buf == null) {
+ buf = lineBuffer = new char[128];
+ }
+
+ int room = buf.length;
+ int offset = 0;
+ int c;
+
+ loop: while (true) {
+ switch (c = in.read()) {
+ case -1:
+ case '\n':
+ break loop;
+
+ case '\r':
+ int c2 = in.read();
+ if ((c2 != '\n') && (c2 != -1)) {
+ if (!(in instanceof SafePushbackInputStream)) {
+ this.in = new SafePushbackInputStream(in);
+ }
+ ((SafePushbackInputStream)in).unread(c2);
+ }
+ break loop;
+
+ default:
+ if (--room < 0) {
+ buf = new char[offset + 128];
+ room = buf.length - offset - 1;
+ System.arraycopy(lineBuffer, 0, buf, 0, offset);
+ lineBuffer = buf;
+ }
+ buf[offset++] = (char) c;
+ break;
+ }
+ }
+ if ((c == -1) && (offset == 0)) {
+ return null;
+ }
+ return String.copyValueOf(buf, 0, offset);
+ }
+
+ /**
+ * See the general contract of the {@code readUTF}
+ * method of {@code DataInput}.
+ *
+ * BufferedReader d
+ * = new BufferedReader(new InputStreamReader(in));
+ *
{@code
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }
{@code
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }
{@code
+ * (byte)(0xff & (v >> 24))
+ * (byte)(0xff & (v >> 16))
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }
{@code
+ * (byte)(0xff & (v >> 56))
+ * (byte)(0xff & (v >> 48))
+ * (byte)(0xff & (v >> 40))
+ * (byte)(0xff & (v >> 32))
+ * (byte)(0xff & (v >> 24))
+ * (byte)(0xff & (v >> 16))
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }
\u0001
through
+ * \u007f
, it is represented
+ * by one byte:
+ * (byte)c
\u0000
+ * or is in the range \u0080
+ * through \u07ff
, then it is
+ * represented by two bytes, to be written
+ * in the order shown: {@code
+ * (byte)(0xc0 | (0x1f & (c >> 6)))
+ * (byte)(0x80 | (0x3f & c))
+ * }
\u0800
+ * through {@code uffff}, then it is
+ * represented by three bytes, to be written
+ * in the order shown: {@code
+ * (byte)(0xe0 | (0x0f & (c >> 12)))
+ * (byte)(0x80 | (0x3f & (c >> 6)))
+ * (byte)(0x80 | (0x3f & c))
+ * }