View Javadoc

1   /*
2    * Copyright 2005,2009 Ivan SZKIBA
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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         // handle end comments
214         if ((line == null) && (comment.length() != 0))
215         {
216             handleComment(comment);
217         }
218 
219         return line;
220     }
221 }