/src/sys/java/fan/sys/InStream.java
Java | 787 lines | 628 code | 85 blank | 74 comment | 209 complexity | d1db1cbe42e329bd306b50612ec3c5ce MD5 | raw file
Possible License(s): CC-BY-SA-3.0
- //
- // Copyright (c) 2006, Brian Frank and Andy Frank
- // Licensed under the Academic Free License version 3.0
- //
- // History:
- // 27 Mar 06 Brian Frank Creation
- //
- package fan.sys;
- import java.math.*;
- import fanx.serial.*;
- /**
- * InStream interface.
- */
- public class InStream
- extends FanObj
- {
- //////////////////////////////////////////////////////////////////////////
- // Construction
- //////////////////////////////////////////////////////////////////////////
- public static InStream make(InStream in)
- {
- InStream self = new InStream();
- make$(self, in);
- return self;
- }
- public static void make$(InStream self, InStream in)
- {
- self.in = in;
- }
- //////////////////////////////////////////////////////////////////////////
- // Obj
- //////////////////////////////////////////////////////////////////////////
- public Type typeof() { return Sys.InStreamType; }
- //////////////////////////////////////////////////////////////////////////
- // Java InputStream
- //////////////////////////////////////////////////////////////////////////
- /**
- * Read a byte using a Java primitive int. Most
- * reads route to this method for efficient mapping to
- * a java.io.InputStream. If we aren't overriding this
- * method, then route back to read() for the subclass
- * to handle.
- */
- public int r()
- {
- Long n = read();
- if (n == null) return -1;
- return n.intValue();
- }
- /**
- * Unread a byte using a Java primitive int. If we aren't
- * overriding this method, then route back to read() for the
- * subclass to handle.
- */
- public InStream unread(int b)
- {
- return unread((long)b);
- }
- /**
- * Read char as primitive int.
- */
- public int rChar()
- {
- if (in != null)
- return in.rChar();
- else
- return charsetDecoder.decode(this);
- }
- /**
- * Unread char as primitive int.
- */
- public InStream unreadChar(int b)
- {
- return unreadChar((long)b);
- }
- //////////////////////////////////////////////////////////////////////////
- // InStream
- //////////////////////////////////////////////////////////////////////////
- public long avail()
- {
- try
- {
- return in.avail();
- }
- catch (NullPointerException e)
- {
- if (in == null)
- throw UnsupportedErr.make(typeof().qname() + " wraps null InStream");
- else
- throw e;
- }
- }
- public Long read()
- {
- try
- {
- return in.read();
- }
- catch (NullPointerException e)
- {
- if (in == null)
- throw UnsupportedErr.make(typeof().qname() + " wraps null InStream");
- else
- throw e;
- }
- }
- public Long readBuf(Buf buf, long n)
- {
- try
- {
- return in.readBuf(buf, n);
- }
- catch (NullPointerException e)
- {
- if (in == null)
- throw UnsupportedErr.make(typeof().qname() + " wraps null InStream");
- else
- throw e;
- }
- }
- public InStream unread(long n)
- {
- try
- {
- in.unread(n);
- return this;
- }
- catch (NullPointerException e)
- {
- if (in == null)
- throw UnsupportedErr.make(typeof().qname() + " wraps null InStream");
- else
- throw e;
- }
- }
- public long skip(long n)
- {
- if (in != null) return in.skip(n);
- long nval = n;
- for (int i=0; i<nval; ++i)
- if (r() < 0) return i;
- return n;
- }
- public Buf readAllBuf()
- {
- try
- {
- long size = FanInt.Chunk;
- Buf buf = Buf.make(size);
- while (readBuf(buf, size) != null);
- buf.flip();
- return buf;
- }
- finally
- {
- try { close(); } catch (Exception e) { e.printStackTrace(); }
- }
- }
- public Buf readBufFully(Buf buf, long n)
- {
- if (buf == null) buf = Buf.make(n);
- long total = n;
- long got = 0;
- while (got < total)
- {
- Long r = readBuf(buf, total-got);
- if (r == null || r.longValue() == 0) throw IOErr.make("Unexpected end of stream");
- got += r.longValue();
- }
- buf.flip();
- return buf;
- }
- public Endian endian()
- {
- return bigEndian ? Endian.big : Endian.little;
- }
- public void endian(Endian endian)
- {
- bigEndian = endian == Endian.big;
- }
- public Long peek()
- {
- Long x = read();
- if (x != null) unread(x);
- return x;
- }
- public long readU1()
- {
- int c = r();
- if (c < 0) throw IOErr.make("Unexpected end of stream");
- return c;
- }
- public long readS1()
- {
- int c = r();
- if (c < 0) throw IOErr.make("Unexpected end of stream");
- return (byte)c;
- }
- public long readU2()
- {
- int c1 = r();
- int c2 = r();
- if ((c1 | c2) < 0) throw IOErr.make("Unexpected end of stream");
- if (bigEndian)
- return c1 << 8 | c2;
- else
- return c2 << 8 | c1;
- }
- public long readS2()
- {
- int c1 = r();
- int c2 = r();
- if ((c1 | c2) < 0) throw IOErr.make("Unexpected end of stream");
- if (bigEndian)
- return (short)(c1 << 8 | c2);
- else
- return (short)(c2 << 8 | c1);
- }
- public long readU4()
- {
- long c1 = r();
- long c2 = r();
- long c3 = r();
- long c4 = r();
- if ((c1 | c2 | c3 | c4) < 0) throw IOErr.make("Unexpected end of stream");
- if (bigEndian)
- return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4;
- else
- return (c4 << 24) + (c3 << 16) + (c2 << 8) + c1;
- }
- public long readS4()
- {
- int c1 = r();
- int c2 = r();
- int c3 = r();
- int c4 = r();
- if ((c1 | c2 | c3 | c4) < 0) throw IOErr.make("Unexpected end of stream");
- if (bigEndian)
- return ((c1 << 24) + (c2 << 16) + (c3 << 8) + c4);
- else
- return ((c4 << 24) + (c3 << 16) + (c2 << 8) + c1);
- }
- public long readS8()
- {
- long c1 = r();
- long c2 = r();
- long c3 = r();
- long c4 = r();
- long c5 = r();
- long c6 = r();
- long c7 = r();
- long c8 = r();
- if ((c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8) < 0) throw IOErr.make("Unexpected end of stream");
- if (bigEndian)
- return ((c1 << 56) + (c2 << 48) + (c3 << 40) + (c4 << 32) +
- (c5 << 24) + (c6 << 16) + (c7 << 8) + c8);
- else
- return ((c8 << 56) + (c7 << 48) + (c6 << 40) + (c5 << 32) +
- (c4 << 24) + (c3 << 16) + (c2 << 8) + c1); }
- public double readF4()
- {
- return Float.intBitsToFloat((int)readS4());
- }
- public double readF8()
- {
- return Double.longBitsToDouble(readS8());
- }
- public BigDecimal readDecimal()
- {
- return FanDecimal.fromStr(readUtf(), true);
- }
- public boolean readBool()
- {
- int n = r();
- if (n < 0) throw IOErr.make("Unexpected end of stream");
- return n != 0;
- }
- public String readUtf()
- {
- // read two-byte length
- int len1 = r();
- int len2 = r();
- if ((len1 | len2) < 0) throw IOErr.make("Unexpected end of stream");
- int utflen = len1 << 8 | len2;
- char[] buf = new char[utflen]; // char buffer we read into
- int bnum = 0, cnum = 0; // byte count, char count
- // read the chars
- int c, c2, c3;
- while (bnum < utflen)
- {
- c = r(); bnum++;
- if (c < 0) throw IOErr.make("Unexpected end of stream");
- switch (c >> 4) {
- case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
- /* 0xxxxxxx*/
- buf[cnum++]=(char)c;
- break;
- case 12: case 13:
- /* 110x xxxx 10xx xxxx*/
- if (bnum >= utflen) throw IOErr.make("UTF encoding error");
- c2 = r(); bnum++;
- if (c2 < 0) throw IOErr.make("Unexpected end of stream");
- if ((c2 & 0xC0) != 0x80) throw IOErr.make("UTF encoding error");
- buf[cnum++]=(char)(((c & 0x1F) << 6) | (c2 & 0x3F));
- break;
- case 14:
- /* 1110 xxxx 10xx xxxx 10xx xxxx */
- if (bnum+1 >= utflen) throw IOErr.make("UTF encoding error");
- c2 = r(); bnum++;
- c3 = r(); bnum++;
- if ((c2|c3) < 0) throw IOErr.make("Unexpected end of stream");
- if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) throw IOErr.make("UTF encoding error");
- buf[cnum++]=(char)(((c & 0x0F) << 12) | ((c2 & 0x3F) << 6) | ((c3 & 0x3F) << 0));
- break;
- default:
- /* 10xx xxxx, 1111 xxxx */
- throw IOErr.make("UTF encoding error");
- }
- }
- // allocate as Str
- return new String(buf, 0, cnum);
- }
- public Charset charset()
- {
- return charset;
- }
- public void charset(Charset charset)
- {
- this.charsetDecoder = charset.newDecoder();
- this.charsetEncoder = charset.newEncoder();
- this.charset = charset;
- }
- public Long readChar()
- {
- if (in != null) return in.readChar();
- int ch = charsetDecoder.decode(this);
- return ch < 0 ? null : Long.valueOf(ch);
- }
- public InStream unreadChar(long c)
- {
- if (in != null)
- in.unreadChar(c);
- else
- charsetEncoder.encode((char)c, this);
- return this;
- }
- public Long peekChar()
- {
- Long x = readChar();
- if (x != null) unreadChar(x);
- return x;
- }
- public String readChars(long n)
- {
- if (n < 0) throw ArgErr.make("readChars n < 0: " + n);
- if (n == 0) return "";
- StringBuilder buf = new StringBuilder(256);
- for (int i=(int)n; i>0; --i)
- {
- int ch = rChar();
- if (ch < 0) throw IOErr.make("Unexpected end of stream");
- buf.append((char)ch);
- }
- return buf.toString();
- }
- public String readLine() { return readLine(FanInt.Chunk); }
- public String readLine(Long max)
- {
- // max limit
- int maxChars = Integer.MAX_VALUE;
- if (max != null)
- {
- long maxLong = max.longValue();
- if (maxLong == 0L) return "";
- if (maxLong < 0L) throw ArgErr.make("Invalid max: " + max);
- if (maxLong < Integer.MAX_VALUE)
- maxChars = (int)maxLong;
- }
- // read first char, if at end of file bail
- int c = rChar();
- if (c < 0) return null;
- // loop reading chars until we hit newline
- // combo or end of stream
- StringBuilder buf = new StringBuilder(256);
- while (true)
- {
- // check for \n, \r\n, or \r
- if (c == '\n') break;
- if (c == '\r')
- {
- c = rChar();
- if (c >= 0 && c != '\n') unreadChar(c);
- break;
- }
- // append to working buffer
- buf.append((char)c);
- if (buf.length() >= maxChars) break;
- // read next char
- c = rChar();
- if (c < 0) break;
- }
- return buf.toString();
- }
- public String readStrToken() { return readStrToken(FanInt.Chunk, null); }
- public String readStrToken(Long max) { return readStrToken(max, null); }
- public String readStrToken(Long max, Func f)
- {
- // max limit
- int maxChars = (max != null) ? max.intValue() : Integer.MAX_VALUE;
- if (maxChars <= 0) return "";
- // read first char, if at end of file bail
- int c = rChar();
- if (c < 0) return null;
- // loop reading chars until our closure returns false
- StringBuilder buf = new StringBuilder();
- while (true)
- {
- // check for \n, \r\n, or \r
- boolean terminate;
- if (f == null)
- terminate = FanInt.isSpace(c);
- else
- terminate = (Boolean)f.call(Long.valueOf(c));
- if (terminate)
- {
- unreadChar(c);
- break;
- }
- // append to working buffer
- buf.append((char)c);
- if (buf.length() >= maxChars) break;
- // read next char
- c = rChar();
- if (c < 0) break;
- }
- return buf.toString();
- }
- public List readAllLines()
- {
- try
- {
- List list = new List(Sys.StrType);
- String line;
- while ((line = readLine()) != null)
- list.add(line);
- return list;
- }
- finally
- {
- try { close(); } catch (Exception e) { e.printStackTrace(); }
- }
- }
- public void eachLine(Func f)
- {
- try
- {
- String line;
- while ((line = readLine()) != null)
- f.call(line);
- }
- finally
- {
- try { close(); } catch (Exception e) { e.printStackTrace(); }
- }
- }
- public String readAllStr() { return readAllStr(true); }
- public String readAllStr(boolean normalizeNewlines)
- {
- try
- {
- char[] buf = new char[4096];
- int n = 0;
- boolean normalize = normalizeNewlines;
- // read characters
- int last = -1;
- while (true)
- {
- int c = rChar();
- if (c < 0) break;
- // grow buffer if needed
- if (n >= buf.length)
- {
- char[] temp = new char[buf.length*2];
- System.arraycopy(buf, 0, temp, 0, n);
- buf = temp;
- }
- // normalize newlines and add to buffer
- if (normalize)
- {
- if (c == '\r') buf[n++] = '\n';
- else if (last == '\r' && c == '\n') {}
- else buf[n++] = (char)c;
- last = c;
- }
- else
- {
- buf[n++] = (char)c;
- }
- }
- return new String(buf, 0, n);
- }
- finally
- {
- try { close(); } catch (Exception e) { e.printStackTrace(); }
- }
- }
- public Object readObj() { return readObj(null); }
- public Object readObj(Map options)
- {
- return new ObjDecoder(this, options).readObj();
- }
- public Map readProps() { return readProps(false); }
- public Map readPropsListVals() { return readProps(true); }
- private Map readProps(boolean listVals) // listVals is Str:Str[]
- {
- Charset origCharset = charset();
- charset(Charset.utf8());
- try
- {
- Map props = new Map(Sys.StrType, listVals ? Sys.StrType.toListOf() : Sys.StrType);
- props.ordered(true);
- StringBuilder name = new StringBuilder();
- StringBuilder val = null;
- int inBlockComment = 0;
- boolean inEndOfLineComment = false;
- int c = ' ', last = ' ';
- int lineNum = 1;
- while (true)
- {
- last = c;
- c = rChar();
- if (c < 0) break;
- // end of line
- if (c == '\n' || c == '\r')
- {
- inEndOfLineComment = false;
- if (last == '\r' && c == '\n') continue;
- String n = FanStr.makeTrim(name);
- if (val != null)
- {
- addProp(props, n, FanStr.makeTrim(val), listVals);
- name = new StringBuilder();
- val = null;
- }
- else if (n.length() > 0)
- throw IOErr.make("Invalid name/value pair [Line " + lineNum + "]");
- lineNum++;
- continue;
- }
- // if in comment
- if (inEndOfLineComment) continue;
- // block comment
- if (inBlockComment > 0)
- {
- if (last == '/' && c == '*') inBlockComment++;
- if (last == '*' && c == '/') inBlockComment--;
- continue;
- }
- // equal
- if (c == '=' && val == null)
- {
- val = new StringBuilder();
- continue;
- }
- // comment
- if (c == '/' && FanInt.isSpace(last))
- {
- int peek = rChar();
- if (peek < 0) break;
- if (peek == '/') { inEndOfLineComment = true; continue; }
- if (peek == '*') { inBlockComment++; continue; }
- unreadChar(peek);
- }
- // escape or line continuation
- if (c == '\\')
- {
- int peek = rChar();
- if (peek < 0) break;
- else if (peek == 'n') c = '\n';
- else if (peek == 'r') c = '\r';
- else if (peek == 't') c = '\t';
- else if (peek == '\\') c = '\\';
- else if (peek == '\r' || peek == '\n')
- {
- // line continuation
- lineNum++;
- if (peek == '\r')
- {
- peek = rChar();
- if (peek != '\n') unreadChar(peek);
- }
- while (true)
- {
- peek = rChar();
- if (peek == ' ' || peek == '\t') continue;
- unreadChar(peek);
- break;
- }
- continue;
- }
- else if (peek == 'u')
- {
- int n3 = hex(rChar());
- int n2 = hex(rChar());
- int n1 = hex(rChar());
- int n0 = hex(rChar());
- if (n3 < 0 || n2 < 0 || n1 < 0 || n0 < 0) throw IOErr.make("Invalid hex value for \\uxxxx [Line " + lineNum + "]");
- c = ((n3 << 12) | (n2 << 8) | (n1 << 4) | n0);
- }
- else throw IOErr.make("Invalid escape sequence [Line " + lineNum + "]");
- }
- // normal character
- if (val == null)
- name.append((char)c);
- else
- val.append((char)c);
- }
- String n = FanStr.makeTrim(name);
- if (val != null)
- addProp(props, n, FanStr.makeTrim(val), listVals);
- else if (n.length() > 0)
- throw IOErr.make("Invalid name/value pair [Line " + lineNum + "]");
- return props;
- }
- finally
- {
- try { close(); } catch (Exception e) { e.printStackTrace(); }
- charset(origCharset);
- }
- }
- static void addProp(Map props, String n, String v, boolean listVals)
- {
- if (listVals)
- {
- List list =(List)props.get(n);
- if (list == null) props.add(n, list = new List(Sys.StrType));
- list.add(v);
- }
- else
- {
- props.add(n, v);
- }
- }
- static int hex(int c)
- {
- if ('0' <= c && c <= '9') return c - '0';
- if ('a' <= c && c <= 'f') return c - 'a' + 10;
- if ('A' <= c && c <= 'F') return c - 'A' + 10;
- return -1;
- }
- public long pipe(OutStream out) { return pipe(out, null, true); }
- public long pipe(OutStream out, Long n) { return pipe(out, n, true); }
- public long pipe(OutStream out, Long toPipe, boolean close)
- {
- try
- {
- long bufSize = FanInt.Chunk;
- Buf buf = Buf.make(bufSize);
- long total = 0;
- if (toPipe == null)
- {
- while (true)
- {
- Long n = readBuf(buf.clear(), bufSize);
- if (n == null) break;
- out.writeBuf(buf.flip(), buf.remaining());
- total += n;
- }
- }
- else
- {
- long toPipeVal = toPipe;
- while (total < toPipeVal)
- {
- if (toPipeVal - total < bufSize) bufSize = toPipeVal - total;
- Long n = readBuf(buf.clear(), bufSize);
- if (n == null) throw IOErr.make("Unexpected end of stream");
- out.writeBuf(buf.flip(), buf.remaining());
- total += n;
- }
- }
- return total;
- }
- finally
- {
- if (close) close();
- }
- }
- public boolean close()
- {
- if (in != null) return in.close();
- return true;
- }
- //////////////////////////////////////////////////////////////////////////
- // Fields
- //////////////////////////////////////////////////////////////////////////
- InStream in;
- boolean bigEndian = true;
- Charset charset = Charset.utf8();
- Charset.Decoder charsetDecoder = charset.newDecoder();
- Charset.Encoder charsetEncoder = charset.newEncoder();
- }