View Javadoc

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             // It's not a special handle
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 }