1 package com.tapina.robe.swi.clib.stdio;
2
3 import java.io.*;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.logging.Logger;
9
10 /***
11 * This class is a representation of a C file pointer.
12 */
13 public abstract class FilePointer {
14 static final int SEQUENCE_BASE = 0x0f00f00f;
15 private static int sequence = SEQUENCE_BASE;
16 private static final List filePointers = new ArrayList(20);
17 private static final Map filePointerMap = new HashMap(20);
18
19 public static final FilePointer stdin = FilePointer.getInstance(System.in);
20 public static final FilePointer stdout = FilePointer.getInstance(System.out);
21 public static final FilePointer stderr = FilePointer.getInstance(System.err);
22
23 private static final class OutputStreamFilePointer extends FilePointer {
24 final OutputStream out;
25
26 public OutputStreamFilePointer(OutputStream out) {
27 this.out = out;
28 }
29
30 public void puts(String s) throws IOException {
31 out.write(s.getBytes("ISO-8859-1"));
32 }
33
34 public void putc(int c) throws IOException {
35 out.write(c);
36 }
37
38 public void ungetc(int c) throws IOException {
39 writeonly();
40 }
41
42 public void write(byte[] data, int offset, int length) throws IOException {
43 out.write(data, offset, length);
44 }
45
46 public byte[] read(int size) throws IOException {
47 writeonly();
48 return null;
49 }
50
51 public int getc() throws IOException {
52 writeonly();
53 return 0;
54 }
55
56 public int getPosition() throws IOException {
57 notRandomAccess();
58 return 0;
59 }
60
61 public int getExtent() throws IOException {
62 notRandomAccess();
63 return 0;
64 }
65
66 public void setPosition(int position) throws IOException {
67 notRandomAccess();
68 }
69
70 private void notRandomAccess() throws IOException {
71 throw new IOException("File is not random access");
72 }
73
74 private void writeonly() throws IOException {
75 throw new IOException("Stream is write only");
76 }
77
78 public boolean eof() throws IOException {
79 throw new IOException("Stream is write only");
80 }
81
82 public void close() throws IOException {
83 out.close();
84 }
85
86 public void flush() throws IOException {
87 out.flush();
88 }
89
90 }
91
92 private static final class InputStreamFilePointer extends FilePointer {
93 final PushbackInputStream in;
94
95 public InputStreamFilePointer(InputStream in) {
96 this.in = new PushbackInputStream(in);
97 }
98
99 public void puts(String s) throws IOException {
100 readonly();
101 }
102
103 private void readonly() throws IOException {
104 throw new IOException("Stream is read-only");
105 }
106
107 public void putc(int c) throws IOException {
108 readonly();
109 }
110
111 public void write(byte[] data, int offset, int length) throws IOException {
112 readonly();
113 }
114
115 public byte[] read(int size) throws IOException {
116 byte[] data = new byte[size];
117 int offset = 0;
118 while (offset != size) {
119 int result = in.read(data, offset, size - offset);
120 if (result == -1) {
121 break;
122 } else {
123 offset += result;
124 }
125 }
126 byte[] truncatedData = new byte[offset];
127 System.arraycopy(data, 0, truncatedData, 0, offset);
128 return truncatedData;
129 }
130
131 public int getc() throws IOException {
132 return in.read();
133 }
134
135 public void ungetc(int c) throws IOException {
136 in.unread(c);
137 }
138
139 public int getPosition() throws IOException {
140 notRandomAccess();
141 return 0;
142 }
143
144 public int getExtent() throws IOException {
145 notRandomAccess();
146 return 0;
147 }
148
149 public void setPosition(int position) throws IOException {
150 notRandomAccess();
151 }
152
153 private void notRandomAccess() throws IOException {
154 throw new IOException("File is not random access");
155 }
156
157 public boolean eof() throws IOException {
158 int c = in.read();
159 if (c == -1) {
160 return true;
161 } else {
162 in.unread(c);
163 return false;
164 }
165 }
166
167 public void close() throws IOException {
168 in.close();
169 }
170
171 public void flush() throws IOException {
172 readonly();
173 }
174 }
175
176 private static final class RandomAccessFilePointer extends FilePointer {
177 final RandomAccessFile file;
178
179 public RandomAccessFilePointer(RandomAccessFile file) {
180 this.file = file;
181 }
182
183 public void puts(String s) throws IOException {
184 file.writeBytes(s);
185 }
186
187 public void putc(int c) throws IOException {
188 file.write(c);
189 }
190
191 public void write(byte[] data, int offset, int length) throws IOException {
192 file.write(data, offset, length);
193 }
194
195 public byte[] read(int size) throws IOException {
196 byte[] data = new byte[size];
197 int offset = 0;
198 while (offset != size) {
199 int result = file.read(data, offset, size - offset);
200 if (result == -1) {
201 break;
202 } else {
203 offset += result;
204 }
205 }
206 byte[] truncatedData = new byte[offset];
207 System.arraycopy(data, 0, truncatedData, 0, offset);
208 return truncatedData;
209 }
210
211 public int getc() throws IOException {
212 return file.readByte();
213 }
214
215 public void ungetc(int c) throws IOException {
216 file.seek(file.getFilePointer() - 1);
217 }
218
219 public int getPosition() throws IOException {
220 return (int) file.getFilePointer();
221 }
222
223 public int getExtent() throws IOException {
224 return (int) file.length();
225 }
226
227 public void setPosition(int position) throws IOException {
228 file.seek(position);
229 }
230
231 public boolean eof() throws IOException {
232 return file.getFilePointer() == file.length();
233 }
234
235 public void close() throws IOException {
236 file.close();
237 }
238
239 public void flush() throws IOException {
240 Logger.getAnonymousLogger().info("flush() operation ignored on random access stream");
241 }
242 }
243
244 private final int handle = sequence++;
245
246 /***
247 * Find a FilePointer object given it's C FILE* handle.
248 * @param handle FILE* value from C.
249 * @return Existing FilePointer object.
250 */
251 public static FilePointer find(int handle) {
252 if (handle > SEQUENCE_BASE) {
253
254 return (FilePointer) filePointers.get(handle - SEQUENCE_BASE);
255 } else {
256 return null;
257 }
258 }
259
260 /***
261 * Create or find existing FilePointer object representing Java PrintStream specified.
262 * @param out PrintStream for which to return FilePointer.
263 * @return FilePointer object representing PrintStream.
264 */
265 public static FilePointer getInstance(PrintStream out) {
266 synchronized (filePointerMap) {
267 if (filePointerMap.containsKey(out)) {
268 return (FilePointer) filePointerMap.get(out);
269 } else {
270 final FilePointer fp = new OutputStreamFilePointer(out);
271 filePointerMap.put(out, fp);
272 filePointers.add(fp);
273 return fp;
274 }
275 }
276 }
277
278
279 /***
280 * Create or find existing FilePointer object representing Java InputStream specified.
281 *
282 * @param in InputStream for which to return FilePointer.
283 * @return FilePointer object representing InputStream.
284 */
285 public static FilePointer getInstance(InputStream in) {
286 synchronized (filePointerMap) {
287 if (filePointerMap.containsKey(in)) {
288 return (FilePointer) filePointerMap.get(in);
289 } else {
290 final FilePointer fp = new InputStreamFilePointer(in);
291 filePointerMap.put(in, fp);
292 filePointers.add(fp);
293 return fp;
294 }
295 }
296 }
297
298 /***
299 * Create or find existing FilePointer object representing Java InputStream specified.
300 *
301 * @param file RandomAccessFile for which to return FilePointer.
302 * @return FilePointer object representing InputStream.
303 */
304 public static FilePointer getInstance(RandomAccessFile file) {
305 synchronized (filePointerMap) {
306 if (filePointerMap.containsKey(file)) {
307 return (FilePointer) filePointerMap.get(file);
308 } else {
309 final FilePointer fp = new RandomAccessFilePointer(file);
310 filePointerMap.put(file, fp);
311 filePointers.add(fp);
312 return fp;
313 }
314 }
315 }
316
317 /***
318 * Get the C FILE* handle for the FilePointer.
319 * @return int handle for C
320 */
321 public int getHandle() {
322 return handle;
323 }
324
325 public abstract void write(byte[] data, int offset, int length) throws IOException;
326 public abstract void puts(String s) throws IOException;
327 public abstract void putc(int c) throws IOException;
328 public abstract void ungetc(int c) throws IOException;
329
330 public abstract int getPosition() throws IOException;
331 public abstract int getExtent() throws IOException;
332 public abstract void setPosition(int position) throws IOException;
333 public abstract boolean eof() throws IOException;
334 public abstract void close() throws IOException;
335 public abstract void flush() throws IOException;
336
337 public abstract byte[] read(int size) throws IOException;
338 public abstract int getc() throws IOException;
339 public final String gets(int maxLength) throws IOException {
340 StringBuffer result = new StringBuffer(maxLength);
341 for (int length = 0; length < maxLength; length++) {
342 int c = getc();
343 if (c == -1) {
344 break;
345 }
346 result.append((char) c);
347 if (c == '\n' || c == '\r') {
348 break;
349 }
350 }
351 return result.toString();
352 }
353
354 }