~ubuntu-branches/ubuntu/utopic/jing-trang/utopic

« back to all changes in this revision

Viewing changes to mod/validate/src/main/com/thaiopensource/validate/auto/RewindableReader.java

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Thibault
  • Date: 2009-09-01 15:53:03 UTC
  • Revision ID: james.westby@ubuntu.com-20090901155303-2kweef05h5v9j3ni
Tags: upstream-20090818
ImportĀ upstreamĀ versionĀ 20090818

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package com.thaiopensource.validate.auto;
 
2
 
 
3
import java.io.IOException;
 
4
import java.io.Reader;
 
5
 
 
6
/**
 
7
 * Rewindable implementation over a reader.
 
8
 * Modified from RewindableInputStream by replacing the input stream with a reader.
 
9
 * @author george
 
10
 */
 
11
public class RewindableReader extends Reader implements Rewindable {
 
12
  static class Block {
 
13
    Block next;
 
14
    final char[] buf;
 
15
    int used = 0;
 
16
    static final int MIN_SIZE = 1024;
 
17
    Block(int minSize) {
 
18
      buf = new char[Math.max(MIN_SIZE, minSize)];
 
19
    }
 
20
 
 
21
    Block() {
 
22
      this(0);
 
23
    }
 
24
 
 
25
    void append(char b) {
 
26
      buf[used++] = b;
 
27
    }
 
28
 
 
29
    void append(char[] b, int off, int len) {
 
30
      System.arraycopy(b, off, buf, used, len);
 
31
      used += len;
 
32
    }
 
33
  }
 
34
 
 
35
  private Block head;
 
36
  /**
 
37
   * If curBlockAvail > 0, then there are curBlockAvail chars available to be
 
38
   * returned starting at curBlockPos in curBlock.buf.
 
39
   */
 
40
  private int curBlockAvail;
 
41
  private Block curBlock;
 
42
  private int curBlockPos;
 
43
  private Block lastBlock;
 
44
  /**
 
45
   * true unless willNotRewind has been called
 
46
   */
 
47
  private boolean saving = true;
 
48
  private final Reader in;
 
49
  private boolean pretendClosed = false;
 
50
  /**
 
51
   * true if we have got an EOF from the underlying Reader
 
52
   */
 
53
  private boolean eof;
 
54
 
 
55
  public RewindableReader(Reader in) {
 
56
    if (in == null)
 
57
      throw new NullPointerException();
 
58
    this.in = in;
 
59
  }
 
60
 
 
61
  public void close() throws IOException {
 
62
    if (saving) {
 
63
      curBlockAvail = 0;
 
64
      curBlock = null;
 
65
      pretendClosed = true;
 
66
    }
 
67
    else {
 
68
      head = null;
 
69
      curBlock = null;
 
70
      lastBlock = null;
 
71
      saving = false;
 
72
      curBlockAvail = 0;
 
73
      in.close();
 
74
    }
 
75
  }
 
76
 
 
77
  public void rewind() {
 
78
    if (!saving)
 
79
      throw new IllegalStateException("rewind() after willNotRewind()");
 
80
    pretendClosed = false;
 
81
    if (head == null)
 
82
      return;
 
83
    curBlock = head;
 
84
    curBlockPos = 0;
 
85
    curBlockAvail = curBlock.used;
 
86
  }
 
87
 
 
88
  public boolean canRewind() {
 
89
    return saving;
 
90
  }
 
91
 
 
92
  public void willNotRewind() {
 
93
    saving = false;
 
94
    head = null;
 
95
    lastBlock = null;
 
96
    if (pretendClosed) {
 
97
      pretendClosed = false;
 
98
      try {
 
99
        in.close();
 
100
      }
 
101
      catch (IOException e) { }
 
102
    }
 
103
  }
 
104
 
 
105
  public int read() throws IOException {
 
106
    if (curBlockAvail > 0) {
 
107
      int c = curBlock.buf[curBlockPos++] & 0xFF;
 
108
      --curBlockAvail;
 
109
      if (curBlockAvail == 0) {
 
110
        curBlock = curBlock.next;
 
111
        if (curBlock != null) {
 
112
          curBlockPos = 0;
 
113
          curBlockAvail = curBlock.used;
 
114
        }
 
115
      }
 
116
      return c;
 
117
    }
 
118
    int c = in.read();
 
119
    if (saving && c != -1) {
 
120
      if (lastBlock == null)
 
121
        lastBlock = head = new Block();
 
122
      else if (lastBlock.used == lastBlock.buf.length)
 
123
        lastBlock = lastBlock.next = new Block();
 
124
      lastBlock.append((char)c);
 
125
    }
 
126
    return c;
 
127
  }
 
128
 
 
129
  public int read(char b[], int off, int len) throws IOException {
 
130
    if (curBlockAvail == 0 && !saving)
 
131
      return in.read(b, off, len);
 
132
    if (b == null)
 
133
      throw new NullPointerException();
 
134
    if (len < 0)
 
135
      throw new IndexOutOfBoundsException();
 
136
    int nRead = 0;
 
137
    if (curBlockAvail != 0) {
 
138
      for (;;) {
 
139
        if (len == 0)
 
140
          return nRead;
 
141
        b[off++] = curBlock.buf[curBlockPos++];
 
142
        --len;
 
143
        nRead++;
 
144
        --curBlockAvail;
 
145
        if (curBlockAvail == 0) {
 
146
          curBlock = curBlock.next;
 
147
          if (curBlock == null)
 
148
            break;
 
149
          curBlockAvail = curBlock.used;
 
150
          curBlockPos = 0;
 
151
        }
 
152
      }
 
153
    }
 
154
    if (len == 0)
 
155
      return nRead;
 
156
    if (eof)
 
157
      return nRead > 0 ? nRead : -1;
 
158
    try {
 
159
      int n = in.read(b, off, len);
 
160
      if (n < 0) {
 
161
        eof = true;
 
162
        return nRead > 0 ? nRead : -1;
 
163
      }
 
164
      nRead += n;
 
165
      if (saving) {
 
166
        if (lastBlock == null)
 
167
          lastBlock = head = new Block(n);
 
168
        else if (lastBlock.buf.length - lastBlock.used < n) {
 
169
          if (lastBlock.used != lastBlock.buf.length) {
 
170
            int free = lastBlock.buf.length - lastBlock.used;
 
171
            lastBlock.append(b, off, free);
 
172
            off += free;
 
173
            n -= free;
 
174
          }
 
175
          lastBlock = lastBlock.next = new Block(n);
 
176
        }
 
177
        lastBlock.append(b, off, n);
 
178
      }
 
179
    }
 
180
    catch (IOException e) {
 
181
      eof = true;
 
182
      if (nRead == 0)
 
183
        throw e;
 
184
    }
 
185
    return nRead;
 
186
  }
 
187
}