1 package org.paneris.util;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.FilterReader;
8 import java.io.IOException;
9
10 public class CRLFFtellReader extends FilterReader {
11
12 private long ftell = 0L;
13 private long markedFtell = 0L;
14
15 /**
16 * Create a new <TT>CRLFFtellReader</TT>.
17 */
18
19 public CRLFFtellReader(BufferedReader in) {
20 super(in);
21 }
22
23 /**
24 * Create a new <TT>CRLFFtellReader</TT>.
25 */
26
27 public CRLFFtellReader(File f) throws FileNotFoundException {
28 this(new BufferedReader(new FileReader(f)));
29 }
30
31 /**
32 * Get the current position.
33 */
34
35 public long getFtell() {
36 return ftell;
37 }
38
39 /**
40 * Read a single character.
41 *
42 * @return The character read, or -1 if the end of the stream has been
43 * reached
44 *
45 * @exception IOException If an I/O error occurs
46 */
47
48 public int read() throws IOException {
49 synchronized (lock) {
50 int c = super.read();
51 if (c != -1) ++ftell;
52 return c;
53 }
54 }
55
56 /**
57 * Read characters into a portion of an array.
58 *
59 * @param cbuf Destination buffer
60 * @param off Offset at which to start storing characters
61 * @param len Maximum number of characters to read
62 *
63 * @return The number of bytes read, or -1 if the end of the stream has
64 * already been reached
65 *
66 * @exception IOException If an I/O error occurs
67 */
68
69 public int read(char cbuf[], int off, int len) throws IOException {
70 synchronized (lock) {
71 if (len <= 0) return 0;
72
73 int n = super.read(cbuf, off, len);
74 if (n > 0) ftell += n;
75 return n;
76 }
77 }
78
79 /**
80 * Skip characters.
81 *
82 * @param n The number of characters to skip
83 *
84 * @return The number of characters actually skipped
85 *
86 * @exception IOException If an I/O error occurs
87 */
88
89 public long skip(long n) throws IOException {
90 synchronized (lock) {
91 long skipped = super.skip(n);
92 ftell += skipped;
93 return skipped;
94 }
95 }
96
97 /**
98 * Mark the present position in the stream. Subsequent calls to reset()
99 * will attempt to reposition the stream to this point, and will also reset
100 * the line number appropriately.
101 *
102 * @param readAheadLimit Limit on the number of characters that may be
103 * read while still preserving the mark. After
104 * reading this many characters, attempting to
105 * reset the stream may fail.
106 *
107 * @exception IOException If an I/O error occurs
108 */
109
110 public void mark(int readAheadLimit) throws IOException {
111 synchronized (lock) {
112 super.mark(readAheadLimit);
113 markedFtell = ftell;
114 }
115 }
116
117 /**
118 * Reset the stream to the most recent mark.
119 *
120 * @exception IOException If the stream has not been marked,
121 * or if the mark has been invalidated
122 */
123
124 public void reset() throws IOException {
125 synchronized (lock) {
126 super.reset();
127 ftell = markedFtell;
128 }
129 }
130
131 /**
132 * Read a line from the stream. FIXME if the line is not terminated with CR+LF,
133 * the <TT>getFtell()</TT> value will henceforth be off by one. Really, an
134 * efficient and 100% correct <TT>CRLFFtellReader</TT> would have to be based on
135 * <TT>BufferedReader</TT>.
136 *
137 * @exception IOException If an I/O error occurs
138 */
139
140 public String readLine() throws IOException {
141 synchronized (lock) {
142 String l = ((BufferedReader)in).readLine();
143 if (l != null) ftell += l.length() + 2;
144 return l;
145 }
146 }
147 }