1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/**
5 *******************************************************************************
6 * Copyright (C) 2001-2015, International Business Machines Corporation and
7 * others. All Rights Reserved.
8 *******************************************************************************
9 */
10
11package android.icu.impl.data;
12
13import java.io.BufferedReader;
14import java.io.Closeable;
15import java.io.IOException;
16import java.io.InputStream;
17import java.io.InputStreamReader;
18import java.io.UnsupportedEncodingException;
19
20import android.icu.impl.ICUData;
21import android.icu.impl.PatternProps;
22
23/**
24 * A reader for text resource data in the current package or the package
25 * of a given class object.  The
26 * resource data is loaded through the class loader, so it will
27 * typically be a file in the same directory as the *.class files, or
28 * a file within a JAR file in the corresponding subdirectory.  The
29 * file must be a text file in one of the supported encodings; when the
30 * resource is opened by constructing a <code>ResourceReader</code>
31 * object the encoding is specified.
32 *
33 * <p>2015-sep-03 TODO: Only used in android.icu.dev.test.format, move there.
34 *
35 * @author Alan Liu
36 * @hide Only a subset of ICU is exposed in Android
37 */
38public class ResourceReader implements Closeable {
39    private BufferedReader reader = null;
40    private String resourceName;
41    private String encoding; // null for default encoding
42    private Class<?> root;
43
44    /**
45     * The one-based line number. Has the special value -1 before the
46     * object is initialized. Has the special value 0 after initialization
47     * but before the first line is read.
48     */
49    private int lineNo;
50
51    /**
52     * Construct a reader object for the text file of the given name
53     * in this package, using the given encoding.
54     * @param resourceName the name of the text file located in this
55     * package's ".data" subpackage.
56     * @param encoding the encoding of the text file; if unsupported
57     * an exception is thrown
58     * @exception UnsupportedEncodingException if
59     * <code>encoding</code> is not supported by the JDK.
60     */
61    public ResourceReader(String resourceName, String encoding)
62        throws UnsupportedEncodingException {
63        this(ICUData.class, "data/" + resourceName, encoding);
64    }
65
66    /**
67     * Construct a reader object for the text file of the given name
68     * in this package, using the default encoding.
69     * @param resourceName the name of the text file located in this
70     * package's ".data" subpackage.
71     */
72    public ResourceReader(String resourceName) {
73        this(ICUData.class, "data/" + resourceName);
74    }
75
76    /**
77     * Construct a reader object for the text file of the given name
78     * in the given class's package, using the given encoding.
79     * @param resourceName the name of the text file located in the
80     * given class's package.
81     * @param encoding the encoding of the text file; if unsupported
82     * an exception is thrown
83     * @exception UnsupportedEncodingException if
84     * <code>encoding</code> is not supported by the JDK.
85     */
86    public ResourceReader(Class<?> rootClass, String resourceName, String encoding)
87        throws UnsupportedEncodingException {
88        this.root = rootClass;
89        this.resourceName = resourceName;
90        this.encoding = encoding;
91        lineNo = -1;
92        _reset();
93    }
94
95         /**
96          * Construct a reader object for the input stream associated with
97          * the given resource name.
98          * @param is the input stream of the resource
99          * @param resourceName the name of the resource
100          */
101          public ResourceReader(InputStream is, String resourceName, String encoding) {
102                   this.root = null;
103         this.resourceName = resourceName;
104         this.encoding = encoding;
105
106         this.lineNo = -1;
107         try {
108             InputStreamReader isr = (encoding == null)
109                 ? new InputStreamReader(is)
110                 : new InputStreamReader(is, encoding);
111
112             this.reader = new BufferedReader(isr);
113             this.lineNo= 0;
114         }
115         catch (UnsupportedEncodingException e) {
116         }
117     }
118
119          /**
120           * Construct a reader object for the input stream associated with
121           * the given resource name.
122           * @param is the input stream of the resource
123           * @param resourceName the name of the resource
124           */
125          public ResourceReader(InputStream is, String resourceName) {
126              this(is, resourceName, null);
127          }
128
129    /**
130     * Construct a reader object for the text file of the given name
131     * in the given class's package, using the default encoding.
132     * @param resourceName the name of the text file located in the
133     * given class's package.
134     */
135    public ResourceReader(Class<?> rootClass, String resourceName) {
136        this.root = rootClass;
137        this.resourceName = resourceName;
138        this.encoding = null;
139        lineNo = -1;
140        try {
141            _reset();
142        } catch (UnsupportedEncodingException e) {}
143    }
144
145    /**
146     * Read and return the next line of the file or <code>null</code>
147     * if the end of the file has been reached.
148     */
149    public String readLine() throws IOException {
150        if (lineNo == 0) {
151            // Remove BOMs
152            ++lineNo;
153            String line = reader.readLine();
154            if (line != null && (line.charAt(0) == '\uFFEF' ||
155                                 line.charAt(0) == '\uFEFF')) {
156                line = line.substring(1);
157            }
158            return line;
159        }
160        ++lineNo;
161        return reader.readLine();
162    }
163
164    /**
165     * Read a line, ignoring blank lines and lines that start with
166     * '#'.
167     * @param trim if true then trim leading Pattern_White_Space.
168     */
169    public String readLineSkippingComments(boolean trim) throws IOException {
170        for (;;) {
171            String line = readLine();
172            if (line == null) {
173                return line;
174            }
175            // Skip over white space
176            int pos = PatternProps.skipWhiteSpace(line, 0);
177            // Ignore blank lines and comment lines
178            if (pos == line.length() || line.charAt(pos) == '#') {
179                continue;
180            }
181            // Process line
182            if (trim) line = line.substring(pos);
183            return line;
184        }
185    }
186
187
188    /**
189     * Read a line, ignoring blank lines and lines that start with
190     * '#'. Do not trim leading Pattern_White_Space.
191     */
192    public String readLineSkippingComments() throws IOException {
193        return readLineSkippingComments(false);
194    }
195
196    /**
197     * Return the one-based line number of the last line returned by
198     * readLine() or readLineSkippingComments(). Should only be called
199     * after a call to one of these methods; otherwise the return
200     * value is undefined.
201     */
202    public int getLineNumber() {
203        return lineNo;
204    }
205
206    /**
207     * Return a string description of the position of the last line
208     * returned by readLine() or readLineSkippingComments().
209     */
210    public String describePosition() {
211        return resourceName + ':' + lineNo;
212    }
213
214    /**
215     * Reset this reader so that the next call to
216     * <code>readLine()</code> returns the first line of the file
217     * again.  This is a somewhat expensive call, however, calling
218     * <code>reset()</code> after calling it the first time does
219     * nothing if <code>readLine()</code> has not been called in
220     * between.
221     */
222    public void reset() {
223        try {
224            _reset();
225        } catch (UnsupportedEncodingException e) {}
226        // We swallow this exception, if there is one.  If the encoding is
227        // invalid, the constructor will have thrown this exception already and
228        // the caller shouldn't use the object afterwards.
229    }
230
231    /**
232     * Reset to the start by reconstructing the stream and readers.
233     * We could also use mark() and reset() on the stream or reader,
234     * but that would cause them to keep the stream data around in
235     * memory.  We don't want that because some of the resource files
236     * are large, e.g., 400k.
237     */
238    private void _reset() throws UnsupportedEncodingException {
239        try {
240            close();
241        } catch (IOException e) {}
242        if (lineNo == 0) {
243            return;
244        }
245        InputStream is = ICUData.getStream(root, resourceName);
246        if (is == null) {
247            throw new IllegalArgumentException("Can't open " + resourceName);
248        }
249
250        InputStreamReader isr =
251            (encoding == null) ? new InputStreamReader(is) :
252                                 new InputStreamReader(is, encoding);
253        reader = new BufferedReader(isr);
254        lineNo = 0;
255    }
256
257    /**
258     * Closes the underlying reader and releases any system resources
259     * associated with it. If the stream is already closed then invoking
260     * this method has no effect.
261     */
262    @Override
263    public void close() throws IOException {
264        if (reader != null) {
265            reader.close();
266            reader = null;
267        }
268    }
269}
270