/*
* `gnu.iou'
* Copyright (C) 2006 John Pritchard.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package gnu.iou ;
/**
* <p> Read/ write byte buffer with extended
* <code>`InputStream'</code> and <code>`OutputStream'</code> API.
*
* <h3>API</h3>
*
* <p> Reading and writing can occur in any order. Writing adds data,
* reading consumes data. Any constructor can be used in any usage.
*
* <p> The <code>`reset()'</code> method as in
* <code>`OutputStream'</code> positions the write pointer to the
* beginning of the internal buffer, unless the
* <code>`mark(int)'</code> method has been used.
*
* <p> The <code>`reset_read()'</code> method positions the read
* pointer to the beginning of the internal buffer, unless the
* <code>`mark_read(int)'</code> method has been used.
*
* <p> The <code>`flush()'</code> method positions the write pointer
* to the beginning of the buffer. After writing has occurred,
* reading will not proceed beyond the written buffer.
*
* <p> The <code>`close()'</code> method resets both pointers and
* markers.
*
* <h3>Not MT Safe</h3>
*
* <p> This class is not synchronized, as most applications have only
* one thread accessing an object, and many synchronizations raise
* java internal and operating system issues.
*
* <p> Applications of this class as a resource shared by multiple
* threads are strongly encouraged to use the instance object as a
* synchronization monitor, as in
*
* <pre>
* synchronized(buf){
* buf.mark_read();
* value = buf.read();
* buf.reset_read();
* buf.write(new_value);
* }
* </pre>
*
* Following this simple rule will permit safe and easy development.
* And as demonstrated in this example, external synchronization is
* effective in all cases while the overhead of method synchronization
* is only rarely useful but always slow.
*
* @author John Pritchard (john@syntelos.org)
*
* @see bbo
* @see bbi
* @see dbo
*/
public class bbuf extends Object {
private final static int GF = 512;
private byte[] buf ;
/**
* buffer read position
*/
private int rc = 0, rc_mark = 0;
/**
* buffer write position (avail == wc - rc)
*/
private int wc = 0, wc_mark = 0;
private int gf = GF;
/**
* Input/ read constructor.
*
* @param input Read- available data (not an empty buffer!)
*/
public bbuf( byte[] input){
super();
if ( null == input)
throw new IllegalArgumentException("Can't construct buffer with null buffer.");
else {
buf = input;
wc = buf.length;
}
}
/**
* Read file into buffer.
*/
public bbuf ( java.io.File fin) throws java.io.IOException {
this((int)fin.length());
this.readFrom(fin);
}
/**
* Copy input into buffer until EOF
*/
public bbuf ( java.io.InputStream in) throws java.io.IOException {
this(GF);
if ( null == in)
throw new IllegalArgumentException("Null input stream for `bbuf'.");
else {
int buflen = 512, bytes;
byte[] readbuf = new byte[buflen];
while ( 0 < (bytes = in.read( readbuf, 0, buflen)))
write( readbuf, 0, bytes);
}
}
/**
* Output/ write constructor.
*/
public bbuf(){
this (GF);
}
/**
* @param gf Internal buffer growth factor, set initial buffer
* size to gf. */
public bbuf( int gf){
super();
buf_gf (gf);
this.buf = new byte[gf];
}
/**
* @return Offset of the last byte written, or negative one before
* the first byte has been written
*/
public int offset_write(){
return (this.wc-1);
}
/**
* @return Offset of the last byte read, or negative one before
* the first byte has been read
*/
public int offset_read(){
return (this.rc-1);
}
/**
* Get or set internal buffer growth factor. Default `GF'.
*
* @param gf If greater than zero, set, otherwise just return
* current value. */
public final int buf_gf( int gf){
if ( 0 < gf)
return (this.gf = gf);
else
return this.gf;
}
public void unread(){
if (0 < this.rc) this.rc -= 1;
}
public void unread(int ch){
if (0 < this.rc)
this.buf[--(this.rc)] = (byte)(ch & 0xff);
else
throw new java.lang.IllegalStateException("Each 'unread' must follow a 'read'.");
}
public void unreadn( int n){
if (n <= this.rc) this.rc -= n;
}
/**
* Look at next byte to be read.
*/
public int peek(){
int av = this.available();
if ( 0 < av)
return this.buf[this.rc]&0xff;
else
return -1;
}
public int read(){
int av = this.available();
if ( 0 < av)
return this.buf[this.rc++]&0xff;
else
return -1;
}
public int read(byte b[]){
return this.read(b,0,b.length);
}
/**
* Copy into buffer as many as buffer- length bytes, or available
* bytes.
*
* @param b Non null buffer to copy into.
*
* @param off Valid offset in buffer `b' to copy to.
*
* @param len Valid number of bytes to copy into `b', usually
* `b.length'.
*
* @returns Number of copied bytes, `len' or `available'. */
public int read(byte b[], int off, int len){
int av = this.available();
if (1 > av)
return -1;
else {
if ( len > av)
len = av;
System.arraycopy(this.buf,this.rc,b,off,len);
this.rc += len;
return len;
}
}
/**
* Read two bytes into a short.
*
* @exception java.io.IOException If two bytes are not available.
*/
public short read2() throws java.io.IOException {
if ( 2 <= available()){
short ch = (short)(buf[rc++]&0xff);
ch <<= 8;
ch |= buf[rc++]&0xff;
return ch;
}
else
throw new java.io.IOException("Unable to read two bytes.");
}
/**
* Read three bytes into an int using network byte order (big endian).
*
* @exception java.io.IOException If three bytes are not available.
*/
public int read3() throws java.io.IOException {
if ( 3 <= available()){
int ch = buf[rc++]&0xff, ch2;
ch <<= 16;
ch2 = buf[rc++]&0xff;
ch2 <<= 8;
ch |= ch2;
ch |= buf[rc++]&0xff;
return ch;
}
else
throw new java.io.IOException("Unable to read three bytes.");
}
/**
* Read four bytes into an int using network byte order (big endian).
*
* @exception java.io.IOException If four bytes are not available.
*/
public int read4() throws java.io.IOException {
if ( 4 <= available()){
int ch = buf[rc++]&0xff, ch2;
ch <<= 24;
ch2 = buf[rc++]&0xff;
ch2 <<= 16;
ch |= ch2;
ch2 = buf[rc++]&0xff;
ch2 <<= 8;
ch |= ch2;
ch |= buf[rc++]&0xff;
return ch;
}
else
throw new java.io.IOException("Unable to read four bytes.");
}
/**
* Read eight bytes into a long using network byte order (big endian).
*
* @exception java.io.IOException If eight bytes are not available.
*/
public long read8() throws java.io.IOException {
if ( 8 <= available()){
long ch = buf[rc++]&0xff, ch2;
ch <<= 56;
ch2 = buf[rc++]&0xff;
ch2 <<= 48;
ch |= ch2;
ch2 = buf[rc++]&0xff;
ch2 <<= 40;
ch |= ch2;
ch2 = buf[rc++]&0xff;
ch2 <<= 32;
ch |= ch2;
ch2 = buf[rc++]&0xff;
ch2 <<= 24;
ch |= ch2;
ch2 = buf[rc++]&0xff;
ch2 <<= 16;
ch |= ch2;
ch2 = buf[rc++]&0xff;
ch2 <<= 8;
ch |= ch2;
ch |= buf[rc++]&0xff;
return ch;
}
else
throw new java.io.IOException("Unable to read eight bytes.");
}
public String read_ascii( int len){
if (len < available()){
String ret = new String(buf, 0, rc, len);
rc += len;
return ret;
}
else return null;
}
/**
* Skip read bytes, or available bytes.
*
* @param n Number of bytes to skip.
*
* @returns Number of bytes skipped.
*/
public int skip_read(int n){
if (0 < n){
rc += (n);
return n;
}
else
return 0;
}
/**
* Skip write bytes, or available bytes.
*
* @param n Number of bytes to skip.
*
* @returns Number of bytes skipped.
*/
public int skip_write(int n){
if (0 < n){
wc += (n);
return n;
}
else
return 0;
}
/**
* Bytes available for reading. (This is also the internal
* reference for bytes available for the read interface.) */
public int available(){
return (this.wc - this.rc);
}
/**
* Reset reading back to first byte of the current buffer, or to
* the last marked position. Also reset the reading mark to zero
* so that two (or more) calls to reset clears any mark.
*/
public void reset_read(){
rc = rc_mark;
rc_mark = 0;
}
/**
* Sets "reset read" (reading) mark to the current position,
* ignoring "limit" because this is a buffer -- we don't need a
* buffer size.
*
* @see limit The limit argument is ignored because this is a
* buffer
*/
public void mark_read(int limit) {
rc_mark = rc;
}
public boolean markSupported_read() {
return true;
}
/**
* Sets "reset" (reading) mark to current position.
*/
public void mark_read() {
rc_mark = rc;
}
/**
* Return bytes read or skipped since last "mark".
*/
public byte[] marked_read(){
int many = rc- rc_mark;
if ( 0 < many){
byte[] ret = new byte[many];
System.arraycopy( buf, rc_mark, ret, 0, many);
return ret;
}
else
return null;
}
/**
* Return bytes read or skipped since last "mark". If drop is
* greater than zero, exclude last drop bytes from returned array
* with no internal effect on read or mark pointers.
*/
public byte[] marked_read(int drop){
if (0 > drop)
throw new java.lang.IllegalArgumentException(String.valueOf(drop));
else {
int many = rc- rc_mark- drop;
if ( 0 < many){
byte[] ret = new byte[many];
System.arraycopy( buf, rc_mark, ret, 0, many);
return ret;
}
else
return null;
}
}
public final String readLine()
throws java.io.IOException
{
int ch, drop = 0;
this.mark_read();
readl:
while (true) {
switch (ch = this.read()) {
case -1:
case '\n':
drop += 1;
break readl;
case '\r':
drop += 1;
switch (ch = this.read()){
case -1:
break readl;
case '\n':
drop += 1;
break readl;
default:
this.unread();
break readl;
}
//break readl;//(unreachable)
default:
break;
}
}
byte[] buf = this.marked_read(drop);
if (null == buf)
return null;
else {
char[] cary = utf8.decode(buf);
return new java.lang.String(cary);
}
}
/**
* Reset writing back to first byte of the current buffer, or to
* the last marked position. Also reset the writing mark to zero
* so that two (or more) calls to reset clears any mark.
*/
public void reset(){
wc = wc_mark;
wc_mark = 0;
}
/**
* Reset reading and writing.
*/
public void resetall(){
this.reset();
this.reset_read();
}
/**
* Sets "reset" (writing) mark to current position. Identical to
* OutputStream's <tt>`mark(int)'</tt>.
*/
public void mark_write() {
wc_mark = wc;
}
/**
* Return bytes written since last "mark".
*/
public byte[] marked_write(){
int many = wc- wc_mark;
if ( 0 < many){
byte[] ret = new byte[many];
System.arraycopy( buf, wc_mark, ret, 0, many);
return ret;
}
else
return null;
}
/**
* Write 16 bits in big endian network byte order.
* @param b 16 bits */
public void write2 ( int b){
if ( wc+2 >= buf.length){
if ( 2 > gf)
buf = growbuf(buf,buf.length+2);
else
buf = growbuf(buf,buf.length+gf);
}
buf[wc++] = (byte)((b & 0xff00)>>>8);
buf[wc++] = (byte)(b & 0xff);
return ;
}
/**
* Write 24 bits in big endian network byte order.
* @param b 24 bits */
public void write3 ( int b){
if ( wc+3 >= buf.length){
if ( 3 > gf)
buf = growbuf(buf,buf.length+3);
else
buf = growbuf(buf,buf.length+gf);
}
buf[wc++] = (byte)((b & 0xff0000)>>>16);
buf[wc++] = (byte)((b & 0xff00)>>>8);
buf[wc++] = (byte)(b & 0xff);
return ;
}
/**
* Write 32 bits in big endian network byte order.
* @param b 32 bits */
public void write4 ( int b){
if ( wc+4 >= buf.length){
if ( 4 > gf)
buf = growbuf(buf,buf.length+4);
else
buf = growbuf(buf,buf.length+gf);
}
buf[wc++] = (byte)((b & 0xff000000)>>>24);
buf[wc++] = (byte)((b & 0xff0000)>>>16);
buf[wc++] = (byte)((b & 0xff00)>>>8);
buf[wc++] = (byte)(b & 0xff);
return ;
}
/**
* Write 64 bits in big endian network byte order.
* @param b 64 bits */
public void write8 ( long b){
if ( wc+8 >= buf.length){
if ( 8 > gf)
buf = growbuf(buf,buf.length+8);
else
buf = growbuf(buf,buf.length+gf);
}
buf[wc++] = (byte)((b & 0xff00000000000000L)>>>56);
buf[wc++] = (byte)((b & 0xff000000000000L)>>>48);
buf[wc++] = (byte)((b & 0xff0000000000L)>>>40);
buf[wc++] = (byte)((b & 0xff00000000L)>>>32);
buf[wc++] = (byte)((b & 0xff000000L)>>>24);
buf[wc++] = (byte)((b & 0xff0000L)>>>16);
buf[wc++] = (byte)((b & 0xff00L)>>>8);
buf[wc++] = (byte)(b & 0xffL);
return ;
}
public void write2 ( short[] ary){
if ( null == ary)
return ;
else {
int alen = ary.length;
for ( int cc = 0; cc < alen; cc++)
write2(ary[cc]);
return ;
}
}
public void write4 ( int[] ary){
if ( null == ary)
return ;
else {
int alen = ary.length;
for ( int cc = 0; cc < alen; cc++){
write4(ary[cc]);
}
return ;
}
}
public void write8 ( long[] ary){
if ( null == ary)
return ;
else {
int alen = ary.length;
for ( int cc = 0; cc < alen; cc++)
write8(ary[cc]);
return ;
}
}
/**
* @param b Eight bit byte value */
public void write(int b){
if ( wc >= buf.length){
buf = growbuf(buf,buf.length+gf);
}
byte bb = (byte)(b & 0xff);//for debugging
buf[wc++] = bb;
return ;
}
/**
* @param b Non null buffer to copy into the internal buffer.
*
* @returns Number of bytes written. */
public int write(byte b[]){
if ( null == b || 0 >= b.length)
return 0;
else
return write(b,0,b.length);
}
/**
* @param b Non null input buffer to copy into the internal buffer.
*
* @param off Offset in input buffer `b' from which to copy
*
* @param len Number of bytes to copy from input buffer `b'.
*
* @returns Number of bytes written. */
public int write(byte b[], int off, int len){
int ni = wc+len;
if ( ni >= buf.length){
if ( len > gf)
buf = growbuf(buf,ni);
else
buf = growbuf(buf,buf.length+gf);
}
System.arraycopy(b,off,buf,wc,len);
wc += len;
return len;
}
/**
* Repeat the byte into the buffer.
*/
public int nwrite ( byte ch, int many){
if (0 < many){
int ni = wc+many;
if ( ni >= buf.length){
if ( many > gf)
buf = growbuf(buf,ni);
else
buf = growbuf(buf,buf.length+gf);
}
for ( int cc = wc; cc < ni; cc++)
buf[cc] = ch;
wc += many;
}
return many;
}
public int write_ascii( String s){
if ( s == null) return 0;
else {
int len = s.length();
if (0 == len) return 0;
else {
byte[] asc = new byte[len];
s.getBytes(0,len,asc,0);
return write(asc,0,len);
}
}
}
/**
* Encode string in UTF-8 and append to buffer. Return number of
* bytes appended to buffer. */
public void print ( String s){
if ( s == null || 0 == s.length())
return ;
else {
byte[] bb = utf8.encode(s);
write(bb);
return ;
}
}
/**
* Encode string with CRLF newline in UTF-8 and append to buffer.
*/
public void println ( String s){
if ( s == null || 0 == s.length())
return ;
else {
print( s);
write(crlf);
return ;
}
}
/**
* Write CRLF newline to buffer. */
public void println (){
write( crlf);
}
/**
* Encode to string (UTF-8) with CRLF newline.
*/
public void println ( Object obj){
append ( obj);
write( crlf);
}
/**
* Add CRLF after each.
*/
public void println ( Object[] objs){
if ( null == objs)
return ;
else {
int many = objs.length;
if ( 1 == many)
println(objs[0]);
else {
for ( int cc = 0; cc < many; cc++){
println(objs[cc]);
}
}
}
}
public void append ( boolean[] ary){
if ( null == ary)
return ;
else {
int alen = ary.length;
write(setopen);
for ( int cc = 0; cc < alen; cc++){
if ( 0 < cc)
write(comma);
if ( ary[cc])
write(trueb);
else
write(falseb);
}
write(setclose);
return ;
}
}
public void append ( short[] ary){
if ( null == ary)
return ;
else {
int alen = ary.length;
write(setopen);
for ( int cc = 0; cc < alen; cc++){
if ( 0 < cc)
write(comma);
print(Integer.toString(ary[cc]));
}
write(setclose);
return ;
}
}
public void append ( int[] ary){
if ( null == ary)
return ;
else {
int alen = ary.length;
write(setopen);
for ( int cc = 0; cc < alen; cc++){
if ( 0 < cc)
write(comma);
print(Integer.toString(ary[cc]));
}
write(setclose);
return ;
}
}
public void append ( long[] ary){
if ( null == ary)
return ;
else {
int alen = ary.length;
write(setopen);
for ( int cc = 0; cc < alen; cc++){
if ( 0 < cc)
write(comma);
print(Long.toString(ary[cc]));
}
write(setclose);
return ;
}
}
public void append ( float[] ary, bbuf bb){
if ( null == ary)
return ;
else {
int alen = ary.length;
write(setopen);
for ( int cc = 0; cc < alen; cc++){
if ( 0 < cc)
write(comma);
print(Float.toString(ary[cc]));
}
write(setclose);
return ;
}
}
public void append ( double[] ary, bbuf bb){
if ( null == ary)
return ;
else {
int alen = ary.length;
write(setopen);
for ( int cc = 0; cc < alen; cc++){
if ( 0 < cc)
write(comma);
print(Double.toString(ary[cc]));
}
write(setclose);
return ;
}
}
public void append ( Object[] oary){
if ( null == oary)
return ;
else {
int oalen = oary.length;
for ( int cc = 0; cc < oalen; cc++)
append( oary[cc]);
return ;
}
}
public void append ( Object o){
if ( null == o)
return ;
else if ( o instanceof byte[]){
write( (byte[])o);
return ;
}
else if ( o instanceof String){
write( utf8.encode( (String)o));
return ;
}
else if ( o instanceof boolean[]){
append( (boolean[])o);
return ;
}
else if ( o instanceof short[]){
append( (short[])o);
return ;
}
else if ( o instanceof int[]){
append( (int[])o);
return ;
}
else if ( o instanceof long[]){
append( (long[])o);
return ;
}
else if ( o instanceof float[]){
append( (float[])o);
return ;
}
else if ( o instanceof double[]){
append( (double[])o);
return ;
}
else if ( o instanceof char[]){
write( utf8.encode( (char[])o));
return ;
}
else if ( null != o){
write( utf8.encode( o.toString()));
return ;
}
}
/**
* Reset reading, writing and "read mark" to the head of the
* current buffer. (Same as "close".) */
public void flush(){
wc = 0;
rc = 0;
wc_mark = 0;
}
/**
* Reset reading, writing and "read mark" to the start. (Same as
* "flush".) */
public void close(){
wc = 0;
rc = 0;
wc_mark = 0;
}
/**
* Naively construct a string on a non- null buffer, otherwise
* return null for an empty buffer. Uses
* <code>`toByteArray()'.</code>
*
* @see #toByteArray() */
public final String bufString(){
byte[] bb = toByteArray();
if ( null == bb)
return null;
else
return new String(bb,0);//(eight bit characters, iso-8859-1)
}
/**
* Copy readable (available) bytes from buffer. If there are no
* available bytes, return null. The same bytes remain readable
* (available). Has no effect on the state of reading or writing.
*/
public final byte[] toByteArray(){
int av = available();
if ( 0 >= av)
return null;
else {
byte[] ret = new byte[av];
System.arraycopy(buf,rc,ret,0,av);
return ret;
}
}
/**
* Return the internal buffer without copying.
*/
public final byte[] verbatim(){
return this.buf;
}
/**
* Return a copy of the internal buffer, verbatim.
*/
public final byte[] dump(){
if ( 0 >= buf.length)
return null;
else {
int bl = buf.length;
byte[] ret = new byte[bl];
System.arraycopy(buf,0,ret,0,bl);
return ret;
}
}
/**
* Discard the internal buffer. Any calls on this object will
* produce null pointer exceptions after this method has been
* called. */
public void destroy(){
this.buf = null;
}
/**
* Same as <tt>`available()'.</tt>
*/
public int length(){
return wc - rc;
}
/**
* Unsynchronized raw buffer copy to output stream using a loop
* for TCP based destinations. This should not be done at the
* same time as read and write ops on this buffer.
*
* <p> Copies from present read point without changing the read or
* write points. */
public int copyOutLoop( java.io.OutputStream out) throws java.io.IOException {
int c0 = rc, length = available();
if ( 0 < length){
byte[] bb = buf;
for ( int cc = c0; cc < length; cc++){
out.write(bb[cc]);
}
return length;
}
else
return 0;
}
/**
* Unsynchronized raw buffer copy to output stream using a loop
* for block devices, <i>etc.</i>. This should not be done at the
* same time as read and write ops on this buffer.
*
* <p> Copies from present read point without changing the read or
* write points. */
public int copyOutArray( java.io.OutputStream out) throws java.io.IOException {
int c0 = rc, length = available();
if ( 0 < length){
byte[] bb = buf;
out.write(bb,c0,length);
return length;
}
else
return 0;
}
/**
* Pass the available bits through UTF-8
*/
public String toString(){
byte[] bits = toByteArray();
if ( null == bits)
return null;
else {
char[] str = utf8.decode(bits);
if ( null == str)
return null;
else
return new String(str);
}
}
/**
* Read the stream contents into memory.
*
* @param in Source stream.
*/
public void readFrom(java.io.InputStream in) throws java.io.IOException {
int ch;
while(-1 < (ch = in.read()))
this.write(ch);
}
/**
* Write the buffer contents to the stream.
*
* @param out Destination stream.
*/
public void writeTo(java.io.OutputStream out) throws java.io.IOException {
int ch;
while(-1 < (ch = this.read()))
out.write(ch);
}
/**
* Read file contents into this buffer.
*
* @param fi Source file. If the file exists, it is read.
*
* @exception java.io.IOException If file permissions don't allow reading.
*/
public void readFrom( java.io.File fi) throws java.io.IOException {
if (fi.exists()){
long filen = fi.length();
int buflen;
if (filen > Integer.MAX_VALUE)
throw new IllegalArgumentException("File is too large to read into a single buffer.");
else {
buflen = (int)filen;
if ( 4096 < buflen)
buflen = 4096;
}
java.io.FileInputStream in = new java.io.FileInputStream(fi);
try {
int read;
byte[] readbuf = new byte[buflen];
while (0 < filen){
read = in.read(readbuf,0,buflen);
this.write(readbuf,0,read);
filen -= read;
}
}
finally {
in.close();
}
}
}
/**
* Read the file contents into memory.
*
* @param buf Optional buffer to fill from offset zero.
*
* @param fi File to read, if it exists.
*
* @exception IllegalArgumentException If the buffer is provided
* but is shorter than the file contents.
*
* @exception java.io.IOException Reading file.
*/
public final static byte[] readFrom( byte[] buf, java.io.File fi) throws java.io.IOException {
if (fi.exists()){
long filen = fi.length();
int buflen;
if (filen > Integer.MAX_VALUE)
throw new IllegalArgumentException("File is too large to read into a single buffer.");
else {
buflen = (int)filen;
if ( buflen > buf.length)
throw new IllegalArgumentException("File is too large ("+buflen+" bytes) to read into argument buffer ("+buf.length+" bytes).");
else if ( null == buf)
buf = new byte[buflen];
}
java.io.FileInputStream in = new java.io.FileInputStream(fi);
try {
int read, bp = 0;
while (0 < buflen){
read = in.read(buf,bp,buflen);
if ( read < buflen){
bp += read;
buflen -= read;
continue;
}
else
return buf;
}
return buf;
}
finally {
in.close();
}
}
else
return buf;
}
/**
* Write buffer to file. File's parent directory will be tested
* for existance and created if necessary.
*
* @param fi Output file.
*
* @exception java.io.IOException Writing file.
*/
public void writeTo( java.io.File fi) throws java.io.IOException {
writeTo( toByteArray(), fi);
}
/**
* Write buffer to file. File's parent directory will be tested
* for existance and created if necessary.
*
* @param buf Buffer (may be null).
*
* @param fi Output file.
*/
public final static void writeTo( byte[] buf, java.io.File fi) throws java.io.IOException {
String p = fi.getParent();
if ( null == p){
fi = new java.io.File(fi.getAbsolutePath());
p = fi.getParent();
}
java.io.File pdir = new java.io.File(p);
if (!pdir.exists())
pdir.mkdirs();
java.io.FileOutputStream out = new java.io.FileOutputStream(fi);
try {
if ( null != buf)
out.write(buf,0,buf.length);
}
finally {
out.close();
}
}
/**
* Array stretch function.
*
* @param src Array, null or extant.
*
* @param to_idx Index that must be accomodated in the extent of
* the source array. */
public final static byte[] growbuf ( byte[] src, int to_idx){
if ( 0 > to_idx)
return src;
else if ( null == src)
return new byte[to_idx+1];
else if ( to_idx >= src.length){
byte[] copier = new byte[to_idx+1];
System.arraycopy(src,0,copier,0,src.length);
return copier;
}
else
return src;
}
private final static byte[] crlf = {'\r','\n'};
private final static byte[] setopen = {'['};
private final static byte[] setclose = {' ',']'};
private final static byte[] comma = {' '};
private final static byte[] trueb = {'t','r','u','e'};
private final static byte[] falseb = {'f','a','l','s','e'};
public final static byte[] toByteArray ( Object[] oary){
bbuf bbu = new bbuf();
bbu.append(oary);
return bbu.toByteArray();
}
public final static byte[] toByteArray ( Object obj){
bbuf bbu = new bbuf();
bbu.append(obj);
return bbu.toByteArray();
}
public final static bbuf toByteArray ( Object obj, bbuf bbu){
if ( null == bbu)
bbu = new bbuf();
bbu.append(obj);
return bbu;
}
public final static bbuf toByteArray ( Object[] objs, bbuf bbu){
if ( null == bbu)
bbu = new bbuf();
bbu.append(objs);
return bbu;
}
public final static byte[] cat ( byte[] a, byte[] b){
if ( null == a)
return b;
else if ( null == b)
return a;
else {
byte[] rcary;
int aclen = a.length, bclen = b.length;
rcary = new byte[aclen+bclen];
System.arraycopy( a, 0, rcary, 0, aclen);
System.arraycopy( b, 0, rcary, aclen, bclen);
return rcary;
}
}
public final static void debugPrint ( byte[] buf, int ofs, int len, java.io.PrintStream out){
if ( null == buf)
out.println("<null buffer>");
else {
len = ((buf.length > len)?(len):(buf.length));
byte bb ;
for ( int fmtc = 0, cc = ofs; cc < len; fmtc++, cc++){
bb = buf[cc];
if ( 0 > bb)
out.print( Integer.toHexString(bb & 0xFF));
else if ( 0x20 > bb || 0x7e < bb)
out.print( String.valueOf((int)bb));
else if ( 0x20 == bb)
out.print( '_');
else
out.print( (char)buf[cc]);
if ( 0 < fmtc && 0 == (fmtc % 5))
out.println();
else
out.write('\t');
}
out.println();
}
}
private final static char[] hexchars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
/**
* <p> binary to hexidecimal</p>
*/
public final static String hex ( byte[] buffer){
if ( null == buffer)
return null;
else {
chbuf strbuf = new chbuf();
int val;
for ( int len = buffer.length, cc = 0; cc < len; cc++){
val = (buffer[cc]&0xff);
strbuf.append(hexchars[(val>>>4)&0xf]);
strbuf.append(hexchars[ val&0xf]);
}
return strbuf.toString();
}
}
}