remove unnecessary import in Persistent.java
[org.ibex.io.git] / src / org / ibex / io / Stream.java
1 // Copyright 2000-2007 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.io;
6
7 import java.io.*;
8 import java.net.*;
9 import java.util.*;
10 import java.util.zip.*;
11 import org.ibex.util.*;
12 import org.ibex.crypto.*;
13
14 // Features:
15 //   - automatically flush writer before reading on linked read/write pairs
16 //   - no checked exceptions thrown
17 //   - unified write(char), print(char), and write(byte)
18 //   - unreading/peeking
19 //   - transcribe
20 //   - append (daisy-chaining)
21 //   - automatically closes input streams when end reached
22
23 /** plays the role of InputStream, OutputStream, Reader and Writer, with logging and unchecked exceptions */
24 public class Stream {
25
26     protected final In in;
27     protected final Out out;
28     private         String newLine = "\r\n";
29
30     public  Stream(byte[] b, int off, int len)       { this.in = new Stream.In(new ByteArrayInputStream(b, off, len)); this.out=null; }
31     public  Stream(InputStream in)                   { this.in = new Stream.In(in); this.out = null; }
32     public  Stream(                OutputStream out) { this.in = null;              this.out = new Stream.Out(out); }
33     public  Stream(InputStream in, OutputStream out) { this.in = new Stream.In(in); this.out = new Stream.Out(out); }
34     public  Stream(String s)                         { this(new ByteArrayInputStream(s.getBytes())); }
35     public  Stream(File f)                           {
36         try { this.in = new Stream.In(new FileInputStream(f)); } catch (IOException e) { ioe(e); throw new Error(); }
37         this.out = null;
38     }
39     public  Stream(Socket s) {
40         try { this.in = new Stream.In(s.getInputStream());    } catch (IOException e) { ioe(e); throw new Error(); }
41         try { this.out = new Stream.Out(s.getOutputStream()); } catch (IOException e) { ioe(e); throw new Error(); }
42     }
43
44     // Main API //////////////////////////////////////////////////////////////////////////////
45
46     public void   setLimit(int limit)              { in.setLimit(limit); }
47     public char   peekc()                          { flush(); return in.getc(true); }
48     public char   getc()                           { flush(); return in.getc(false); }
49     public String readln()                         { flush(); return in.readln(); }
50     public void   print(String s)                  { out.write(s); flush(); }
51     public void   println(String s)                { print(s); print(newLine); }
52     public void   flush()                          { if (out != null) out.flushWriter(); }
53     public void writeBytes(byte[] b, int off, int len) { try { out.write(b, off, len); } catch (IOException e) { ioe(e); } }
54     public int    read(byte[] b, int off, int len) { flush(); return in.readBytes(b, off, len); }
55     public int    read(char[] c, int off, int len) { flush(); return in.readChars(c, off, len); }
56     public int    skip(int len) { return in.skip(len); }
57     public void   close()                          { try { if (in!=null) in.close(); } finally { if (out!=null) out.close(); } }
58     public void   setNewline(String s)             { newLine = s; }
59     public InputStream getInputStream() { return in; }
60
61     public void   setInputDigest(Digest d) { in.bbis.digest = d; }
62
63     private static class Out extends BufferedOutputStream {
64         private Writer writer = new OutputStreamWriter(this);
65         public Out(OutputStream out) { super(out); }
66         public  void close() { try { super.close(); } catch (Exception e) { Log.error(this, e); } }
67         public  void write(String s) { try { writer.write(s); } catch (IOException e) { ioe(e); } }
68         private void flushWriter() { try { writer.flush(); } catch (IOException e) { ioe(e); } }
69         private boolean flushing = false;
70         public  void flush() {
71             if (flushing) return;
72             try {
73                 flushing = true;
74                 try {
75                     writer.flush();
76                 } finally { flushing = false; }
77                 super.flush();
78             } catch (IOException e) { ioe(e); }
79         }
80     }
81
82     private class In extends InputStream {
83         private ByteBufInputStream bbis;
84         private CharBufReader cbr;
85         public  Reader reader;
86         private Writer unreader;
87
88         public char getc(boolean peek) { return cbr.getc(peek); }
89         public String readln() { return cbr.readln(); }
90         public int skip(int len) { return bbis.skip(len); }
91         public int read() { return bbis.read(); }
92         public int read(byte[] b) { try { return bbis.read(b); } catch (IOException e) { ioe(e); return 0; } }
93         public int read(byte[] b, int off, int len) { return bbis.read(b, off, len); }
94         public void close() { try { cbr.close(); } catch (Exception e) { Log.error(this, e); } }
95         public int readBytes(byte[] b, int off, int len) { return bbis.read(b, off, len); }
96         public int readChars(char[] c, int off, int len) { return cbr.read(c, off, len); }
97         public void setLimit(int len) { bbis.setLimit(len); }
98
99         public In(InputStream in) {
100             bbis = new ByteBufInputStream(in) {
101                     public void preread() {
102                         cbr.unbuffer(unreader);
103                         try {
104                             if (!cbr.ready()) return;
105                         } catch (IOException e) { ioe(e); }
106                         char[] c = new char[20];
107                         while(true) {
108                             try {
109                                 if (!cbr.ready()) break;
110                                 int numread = cbr.read(c, 0, c.length);
111                                 if (numread == -1) break;
112                                 unreader.write(c, 0, numread);
113                             } catch (IOException e) { ioe(e); }
114                         }
115                     }
116                 };
117             unreader = new OutputStreamWriter(new UnReaderStream(bbis));
118             cbr = new CharBufReader(new InputStreamReader(bbis));
119         }
120     }
121
122     // Utilities: append() and transcribe() ///////////////////////////////////////////////////////
123
124     public Stream append(String in_next) { return appendStream(new Stream(in_next)); }
125     public Stream appendStream(Stream in_next) { in.bbis.appendStream(in_next); return this; }
126
127     public void transcribe(Stream out) { transcribe(out, false); }
128     public void transcribe(Stream out, boolean close) {
129         byte[] buf = new byte[1024];
130         while(true) {
131             int numread = in.read(buf, 0, buf.length);
132             if (numread==-1) { in.close(); break; }
133             out.writeBytes(buf, 0, numread);
134         }
135         if (close) out.close();
136     }
137
138     public void transcribe(StringBuffer out) {
139         char[] buf = new char[1024];
140         while(true) {
141             int numread = in.readChars(buf, 0, buf.length);
142             if (numread==-1) { in.close(); return; }
143             out.append(buf, 0, numread);
144         }
145     }
146
147     public static int countLines(Stream s) {
148         int ret = 0;
149         while(s.readln() != null) ret++;
150         s.close();
151         return ret;
152     }
153
154     // FIXME: ugly
155     public static int countBytes(Stream s) {
156         int ret = 0;
157         while(s.in.read() != -1) ret++;
158         s.close();
159         return ret;
160     }
161
162     // Exceptions //////////////////////////////////////////////////////////////////////////////
163
164     static int ioe(IOException e) {
165         if (e instanceof SocketException && e.toString().indexOf("Connection reset")!=-1)
166             throw new Closed(e.getMessage());
167         throw new StreamException(e);
168     }
169     public static class StreamException extends RuntimeException {
170         public StreamException(Exception e) { super(e); }
171         public StreamException(String s)    { super(s); }
172     }
173     public static class EOF             extends StreamException  { public EOF() { super("End of stream"); } }
174     public static class Closed          extends StreamException  { public Closed(String s) { super(s); } }
175 }