package com.macfaq.io; import java.io.*; public class SourceReader extends FilterReader { public SourceReader(InputStream in) { this(new InputStreamReader(in)); } public SourceReader(Reader in) { super(in); } private int buffer = -1; public int read() throws IOException { if (this.buffer != -1) { int c = this.buffer; this.buffer = -1; return c; } int c = in.read(); if (c != '\\') return c; int next = in.read(); if (next != 'u' ) { // This is not a Unicode escape this.buffer = next; return c; } // read next 4 hex digits // If the next four chars do not make a valid hex digit // this is not a valid .java file and you need // a compiler error StringBuffer sb = new StringBuffer(); sb.append((char) in.read()); sb.append((char) in.read()); sb.append((char) in.read()); sb.append((char) in.read()); String hex = sb.toString(); try { return Integer.valueOf(hex, 16).intValue(); } catch (NumberFormatException e) { throw new IOException("Bad Unicode escape: \\u" + hex); } } private boolean endOfStream = false; public int read(char[] text, int offset, int length) throws IOException { if (endOfStream) return -1; int numRead = 0; for (int i = offset; i < offset+length; i++) { int temp = this.read(); if (temp == -1) { this.endOfStream = true; break; } text[i] = (char) temp; numRead++; } return numRead; } public long skip(long n) throws IOException { char[] c = new char[(int) n]; int numSkipped = this.read(c); return numSkipped; } // test public static void main(String[] args) { for (int i = 0; i < args.length; i++) { try { InputStream in = new FileInputStream(args[i]); Reader r = new SourceReader(in); char[] text = new char[128]; while (true) { int n = r.read(text); if (n == -1) { System.out.println("End of file"); System.out.flush(); break; } for (int j = 0; j < n; j++) { System.out.print(text[j]); } } } catch (IOException e) { System.err.println(e); } } // generate test data /* for (int i = 32; i < 127; i++) { System.out.println("// " + (char) i + "\t\\\\u00" + Integer.toHexString(i) + "\t\\u00" + Integer.toHexString(i)); } */ } } // For testing some Unicode escapes when this program is run on itself: // \\u0020 \u0020 // ! \\u0021 \u0021 // " \\u0022 \u0022 // # \\u0023 \u0023 // $ \\u0024 \u0024 // % \\u0025 \u0025 // & \\u0026 \u0026 // ' \\u0027 \u0027 // ( \\u0028 \u0028 // ) \\u0029 \u0029 // * \\u002a \u002a // + \\u002b \u002b // , \\u002c \u002c // - \\u002d \u002d // . \\u002e \u002e // / \\u002f \u002f // 0 \\u0030 \u0030 // 1 \\u0031 \u0031 // 2 \\u0032 \u0032 // 3 \\u0033 \u0033 // 4 \\u0034 \u0034 // 5 \\u0035 \u0035 // 6 \\u0036 \u0036 // 7 \\u0037 \u0037 // 8 \\u0038 \u0038 // 9 \\u0039 \u0039 // : \\u003a \u003a // ; \\u003b \u003b // < \\u003c \u003c // = \\u003d \u003d // > \\u003e \u003e // ? \\u003f \u003f // @ \\u0040 \u0040 // A \\u0041 \u0041 // B \\u0042 \u0042 // C \\u0043 \u0043 // D \\u0044 \u0044 // E \\u0045 \u0045 // F \\u0046 \u0046 // G \\u0047 \u0047 // H \\u0048 \u0048 // I \\u0049 \u0049 // J \\u004a \u004a // K \\u004b \u004b // L \\u004c \u004c // M \\u004d \u004d // N \\u004e \u004e // O \\u004f \u004f // P \\u0050 \u0050 // Q \\u0051 \u0051 // R \\u0052 \u0052 // S \\u0053 \u0053 // T \\u0054 \u0054 // U \\u0055 \u0055 // V \\u0056 \u0056 // W \\u0057 \u0057 // X \\u0058 \u0058 // Y \\u0059 \u0059 // Z \\u005a \u005a // [ \\u005b \u005b // \ \\u005c \u005c // ] \\u005d \u005d // ^ \\u005e \u005e // _ \\u005f \u005f // ` \\u0060 \u0060 // a \\u0061 \u0061 // b \\u0062 \u0062 // c \\u0063 \u0063 // d \\u0064 \u0064 // e \\u0065 \u0065 // f \\u0066 \u0066 // g \\u0067 \u0067 // h \\u0068 \u0068 // i \\u0069 \u0069 // j \\u006a \u006a // k \\u006b \u006b // l \\u006c \u006c // m \\u006d \u006d // n \\u006e \u006e // o \\u006f \u006f // p \\u0070 \u0070 // q \\u0071 \u0071 // r \\u0072 \u0072 // s \\u0073 \u0073 // t \\u0074 \u0074 // u \\u0075 \u0075 // v \\u0076 \u0076 // w \\u0077 \u0077 // x \\u0078 \u0078 // y \\u0079 \u0079 // z \\u007a \u007a // { \\u007b \u007b // | \\u007c \u007c // } \\u007d \u007d // ~ \\u007e \u007e