View Javadoc

1   package org.paneris.messageboard.receivemail;
2   
3   import java.io.FilterInputStream;
4   import java.io.IOException;
5   import java.io.PushbackInputStream;
6   
7   /**
8    * A stream comprising everything in an underlying stream up to the
9    * first line containing only a fullstop.
10   *
11   * Once the <TT>DotTerminatedInputStream</TT> has reported
12   * end-of-file, the underlying stream can be used again to read the
13   * data from the dot-line up to its own end-of-file.
14   */
15  
16  class DotTerminatedInputStream extends FilterInputStream {
17    private static final int
18        TEXT = 0, FIRSTCR = 1, FIRSTNL = 2, DOT = 3, SECONDCR = 4, TERMINATED = 5,
19        POP = 6;
20  
21    private int state = FIRSTNL;
22    private int state1 = -1;
23    private int byte1 = -1;
24    private byte[] pushedBack = new byte[4];
25    private int pushedBackIn = 0;
26    private int pushedBackOut = 0;
27  
28    /**
29     * @param in          the underlying stream: must be a
30     *                            <TT>PushbackInputStream</TT> because
31     *                            it's theoretically possible to end up
32     *                            with a character that has to be pushed
33     *                            back
34     */
35  
36    public DotTerminatedInputStream(PushbackInputStream in) {
37      super(in);
38    }
39  
40    private int superRead() throws IOException {
41      if (byte1 == -1) return super.read();
42      else {
43        int it = byte1;
44        byte1 = -1;
45        return it;
46      }
47    }
48  
49    private void pushBack(byte b) {
50      if (pushedBackIn == pushedBack.length) {
51        // in fact this doesn't happen
52        byte[] pushedBack_ = new byte[pushedBack.length * 2];
53        System.arraycopy(pushedBack, 0, pushedBack_, 0, pushedBack.length);
54        pushedBack = pushedBack_;
55      }
56  
57      pushedBack[pushedBackIn++] = b;
58    }
59  
60    public synchronized int read() throws IOException {
61      int b;
62      for (;;) {
63        switch (state) {
64      case TERMINATED:
65        pushedBack = null;
66        return -1;
67  
68      case POP:
69        if (pushedBackOut < pushedBackIn) {
70          return pushedBack[pushedBackOut++];
71        }
72        else {
73          pushedBackOut = 0;
74          pushedBackIn = 0;
75          state = state1;
76        }
77        break;
78  
79      case TEXT:
80        switch (b = superRead()) {
81          case '\r': state = FIRSTCR; pushBack((byte)13); break;
82          case '\n': state = FIRSTNL; pushBack((byte)10); break;
83              case -1:   state = POP; state1 = TERMINATED; break;
84          default:   return b;
85        }
86        break;
87  
88      case FIRSTCR:
89        switch (b = superRead()) {
90          case '\n': state = FIRSTNL; pushBack((byte)10); break;
91          case '\r': state = POP; state1 = TEXT; byte1 = '\r'; break;
92              case -1:   state = POP; state1 = TERMINATED; break;
93          default:   state = POP; state1 = TEXT; byte1 = b; break;
94        }
95        break;
96  
97      case FIRSTNL:
98        switch (b = superRead()) {
99          case '.': state = DOT; pushBack((byte)46); break;
100         case '\n': state = POP; state1 = TEXT; byte1 = '\n'; break;
101         case '\r': state = POP; state1 = TEXT; byte1 = '\r'; break;
102             case -1:   state = POP; state1 = TERMINATED; break;
103         default:   state = POP; state1 = TEXT; byte1 = b; break;
104       }
105       break;
106 
107     case DOT:
108       switch (b = superRead()) {
109         case '\n': state = TERMINATED; break;
110         case '\r': state = SECONDCR; break;
111             case -1:   state = POP; state1 = TERMINATED; break;
112         default:   state = POP; state1 = TEXT; byte1 = b; break;
113       }
114       break;
115 
116     case SECONDCR:
117       if ((b = superRead()) != '\n')
118         ((PushbackInputStream)in).unread(b);
119       state = TERMINATED;
120       break;
121       }
122     }
123   }
124 
125   public synchronized int read(byte[] b, int off, int len) throws IOException {
126     if (len <= 0) {
127       return 0;
128     }
129 
130     int c = read();
131     if (c == -1) {
132       return -1;
133     }
134     b[off] = (byte)c;
135 
136     int i = 1;
137     try {
138       for (; i < len ; i++) {
139         c = read();
140         if (c == -1) {
141           break;
142         }
143         if (b != null) {
144           b[off + i] = (byte)c;
145         }
146        }
147     } catch (IOException ee) {
148       ; //Can't see why this is being ignored
149     }
150     return i;
151   }
152 
153   public synchronized long skip(long n) throws IOException {
154     while (n > 0L && read() != -1) --n;
155     return n;
156   }
157 }