1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.ini4j.spi;
17
18 import org.ini4j.Config;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.LineNumberReader;
23 import java.io.Reader;
24
25 import java.net.URL;
26
27 class IniSource
28 {
29 public static final char INCLUDE_BEGIN = '<';
30 public static final char INCLUDE_END = '>';
31 public static final char INCLUDE_OPTIONAL = '?';
32 private static final char ESCAPE_CHAR = '\\';
33 private URL _base;
34 private IniSource _chain;
35 private final String _commentChars;
36 private final Config _config;
37 private final HandlerBase _handler;
38 private final LineNumberReader _reader;
39
40 IniSource(InputStream input, HandlerBase handler, String comments, Config config)
41 {
42 this(new UnicodeInputStreamReader(input, config.getFileEncoding()), handler, comments, config);
43 }
44
45 IniSource(Reader input, HandlerBase handler, String comments, Config config)
46 {
47 _reader = new LineNumberReader(input);
48 _handler = handler;
49 _commentChars = comments;
50 _config = config;
51 }
52
53 IniSource(URL input, HandlerBase handler, String comments, Config config) throws IOException
54 {
55 this(new UnicodeInputStreamReader(input.openStream(), config.getFileEncoding()), handler, comments, config);
56 _base = input;
57 }
58
59 int getLineNumber()
60 {
61 int ret;
62
63 if (_chain == null)
64 {
65 ret = _reader.getLineNumber();
66 }
67 else
68 {
69 ret = _chain.getLineNumber();
70 }
71
72 return ret;
73 }
74
75 String readLine() throws IOException
76 {
77 String line;
78
79 if (_chain == null)
80 {
81 line = readLineLocal();
82 }
83 else
84 {
85 line = _chain.readLine();
86 if (line == null)
87 {
88 _chain = null;
89 line = readLine();
90 }
91 }
92
93 return line;
94 }
95
96 private void close() throws IOException
97 {
98 _reader.close();
99 }
100
101 private int countEndingEscapes(String line)
102 {
103 int escapeCount = 0;
104
105 for (int i = line.length() - 1; (i >= 0) && (line.charAt(i) == ESCAPE_CHAR); i--)
106 {
107 escapeCount++;
108 }
109
110 return escapeCount;
111 }
112
113 private void handleComment(StringBuilder buff)
114 {
115 if (buff.length() != 0)
116 {
117 buff.deleteCharAt(buff.length() - 1);
118 _handler.handleComment(buff.toString());
119 buff.delete(0, buff.length());
120 }
121 }
122
123 private String handleInclude(String input) throws IOException
124 {
125 String line = input;
126
127 if (_config.isInclude() && (line.length() > 2) && (line.charAt(0) == INCLUDE_BEGIN) && (line.charAt(line.length() - 1) == INCLUDE_END))
128 {
129 line = line.substring(1, line.length() - 1).trim();
130 boolean optional = line.charAt(0) == INCLUDE_OPTIONAL;
131
132 if (optional)
133 {
134 line = line.substring(1).trim();
135 }
136
137 URL loc = (_base == null) ? new URL(line) : new URL(_base, line);
138
139 if (optional)
140 {
141 try
142 {
143 _chain = new IniSource(loc, _handler, _commentChars, _config);
144 }
145 catch (IOException x)
146 {
147 assert true;
148 }
149 finally
150 {
151 line = readLine();
152 }
153 }
154 else
155 {
156 _chain = new IniSource(loc, _handler, _commentChars, _config);
157 line = readLine();
158 }
159 }
160
161 return line;
162 }
163
164 private String readLineLocal() throws IOException
165 {
166 String line = readLineSkipComments();
167
168 if (line == null)
169 {
170 close();
171 }
172 else
173 {
174 line = handleInclude(line);
175 }
176
177 return line;
178 }
179
180 private String readLineSkipComments() throws IOException
181 {
182 String line;
183 StringBuilder comment = new StringBuilder();
184 StringBuilder buff = new StringBuilder();
185
186 for (line = _reader.readLine(); line != null; line = _reader.readLine())
187 {
188 line = line.trim();
189 if (line.length() == 0)
190 {
191 handleComment(comment);
192 }
193 else if ((_commentChars.indexOf(line.charAt(0)) >= 0) && (buff.length() == 0))
194 {
195 comment.append(line.substring(1));
196 comment.append(_config.getLineSeparator());
197 }
198 else
199 {
200 handleComment(comment);
201 if (!_config.isEscapeNewline() || ((countEndingEscapes(line) & 1) == 0))
202 {
203 buff.append(line);
204 line = buff.toString();
205
206 break;
207 }
208
209 buff.append(line.subSequence(0, line.length() - 1));
210 }
211 }
212
213
214 if ((line == null) && (comment.length() != 0))
215 {
216 handleComment(comment);
217 }
218
219 return line;
220 }
221 }