/** ******************************************************************************* * Copyright (C) 2001-2009, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ package com.ibm.icu.impl.data; import java.io.*; import com.ibm.icu.impl.ICUData; import com.ibm.icu.impl.Utility; /** * A reader for text resource data in the current package or the package * of a given class object. The * resource data is loaded through the class loader, so it will * typically be a file in the same directory as the *.class files, or * a file within a JAR file in the corresponding subdirectory. The * file must be a text file in one of the supported encodings; when the * resource is opened by constructing a ResourceReader * object the encoding is specified. * * @author Alan Liu */ public class ResourceReader { private BufferedReader reader; private String resourceName; private String encoding; // null for default encoding private Class root; /** * The one-based line number. Has the special value -1 before the * object is initialized. Has the special value 0 after initialization * but before the first line is read. */ private int lineNo; /** * Construct a reader object for the text file of the given name * in this package, using the given encoding. * @param resourceName the name of the text file located in this * package's ".data" subpackage. * @param encoding the encoding of the text file; if unsupported * an exception is thrown * @exception UnsupportedEncodingException if * encoding is not supported by the JDK. */ public ResourceReader(String resourceName, String encoding) throws UnsupportedEncodingException { this(ICUData.class, "data/" + resourceName, encoding); } /** * Construct a reader object for the text file of the given name * in this package, using the default encoding. * @param resourceName the name of the text file located in this * package's ".data" subpackage. */ public ResourceReader(String resourceName) { this(ICUData.class, "data/" + resourceName); } /** * Construct a reader object for the text file of the given name * in the given class's package, using the given encoding. * @param resourceName the name of the text file located in the * given class's package. * @param encoding the encoding of the text file; if unsupported * an exception is thrown * @exception UnsupportedEncodingException if * encoding is not supported by the JDK. */ public ResourceReader(Class rootClass, String resourceName, String encoding) throws UnsupportedEncodingException { this.root = rootClass; this.resourceName = resourceName; this.encoding = encoding; lineNo = -1; _reset(); } /** * Construct a reader object for the input stream associated with * the given resource name. * @param is the input stream of the resource * @param resourceName the name of the resource */ public ResourceReader(InputStream is, String resourceName, String encoding) { this.root = null; this.resourceName = resourceName; this.encoding = encoding; this.lineNo = -1; try { InputStreamReader isr = (encoding == null) ? new InputStreamReader(is) : new InputStreamReader(is, encoding); this.reader = new BufferedReader(isr); this.lineNo= 0; } catch (UnsupportedEncodingException e) { } } /** * Construct a reader object for the input stream associated with * the given resource name. * @param is the input stream of the resource * @param resourceName the name of the resource */ public ResourceReader(InputStream is, String resourceName) { this(is, resourceName, null); } /** * Construct a reader object for the text file of the given name * in the given class's package, using the default encoding. * @param resourceName the name of the text file located in the * given class's package. */ public ResourceReader(Class rootClass, String resourceName) { this.root = rootClass; this.resourceName = resourceName; this.encoding = null; lineNo = -1; try { _reset(); } catch (UnsupportedEncodingException e) {} } /** * Read and return the next line of the file or null * if the end of the file has been reached. */ public String readLine() throws IOException { if (lineNo == 0) { // Remove BOMs ++lineNo; String line = reader.readLine(); if (line.charAt(0) == '\uFFEF' || line.charAt(0) == '\uFEFF') { line = line.substring(1); } return line; } ++lineNo; return reader.readLine(); } /** * Read a line, ignoring blank lines and lines that start with * '#'. * @param trim if true then trim leading rule white space. */ public String readLineSkippingComments(boolean trim) throws IOException { for (;;) { String line = readLine(); if (line == null) { return line; } // Skip over white space int pos = Utility.skipWhitespace(line, 0); // Ignore blank lines and comment lines if (pos == line.length() || line.charAt(pos) == '#') { continue; } // Process line if (trim) line = line.substring(pos); return line; } } /** * Read a line, ignoring blank lines and lines that start with * '#'. Do not trim leading rule white space. */ public String readLineSkippingComments() throws IOException { return readLineSkippingComments(false); } /** * Return the one-based line number of the last line returned by * readLine() or readLineSkippingComments(). Should only be called * after a call to one of these methods; otherwise the return * value is undefined. */ public int getLineNumber() { return lineNo; } /** * Return a string description of the position of the last line * returned by readLine() or readLineSkippingComments(). */ public String describePosition() { return resourceName + ':' + lineNo; } /** * Reset this reader so that the next call to * readLine() returns the first line of the file * again. This is a somewhat expensive call, however, calling * reset() after calling it the first time does * nothing if readLine() has not been called in * between. */ public void reset() { try { _reset(); } catch (UnsupportedEncodingException e) {} // We swallow this exception, if there is one. If the encoding is // invalid, the constructor will have thrown this exception already and // the caller shouldn't use the object afterwards. } /** * Reset to the start by reconstructing the stream and readers. * We could also use mark() and reset() on the stream or reader, * but that would cause them to keep the stream data around in * memory. We don't want that because some of the resource files * are large, e.g., 400k. */ private void _reset() throws UnsupportedEncodingException { if (lineNo == 0) { return; } InputStream is = ICUData.getStream(root, resourceName); if (is == null) { throw new IllegalArgumentException("Can't open " + resourceName); } InputStreamReader isr = (encoding == null) ? new InputStreamReader(is) : new InputStreamReader(is, encoding); reader = new BufferedReader(isr); lineNo = 0; } }