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;
17  
18  import org.ini4j.spi.ServiceFinder;
19  
20  import org.xml.sax.Attributes;
21  import org.xml.sax.InputSource;
22  import org.xml.sax.SAXException;
23  import org.xml.sax.helpers.DefaultHandler;
24  
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.InputStreamReader;
28  import java.io.Reader;
29  
30  import java.net.URL;
31  
32  import java.util.Locale;
33  
34  import javax.xml.parsers.SAXParserFactory;
35  
36  public class IniParser extends AbstractParser
37  {
38      private static final String COMMENTS = ";#";
39      private static final String OPERATORS = ":=";
40  
41      public static final char SECTION_BEGIN = '[';
42      public static final char SECTION_END = ']';
43  
44      public IniParser()
45      {
46          super(OPERATORS, COMMENTS);
47      }
48  
49      public static IniParser newInstance()
50      {
51          return ServiceFinder.findService(IniParser.class);
52      }
53  
54      public static IniParser newInstance(Config config)
55      {
56          IniParser instance = newInstance();
57  
58          instance.setConfig(config);
59  
60          return instance;
61      }
62  
63      public void parse(InputStream input, IniHandler handler) throws IOException, InvalidIniFormatException
64      {
65          parse(newIniSource(input), handler);
66      }
67  
68      public void parse(Reader input, IniHandler handler) throws IOException, InvalidIniFormatException
69      {
70          parse(newIniSource(input), handler);
71      }
72  
73      public void parse(URL input, IniHandler handler) throws IOException, InvalidIniFormatException
74      {
75          parse(newIniSource(input), handler);
76      }
77  
78      public void parseXML(InputStream input, IniHandler handler) throws IOException, InvalidIniFormatException
79      {
80          parseXML(new InputStreamReader(input), handler);
81      }
82  
83      public void parseXML(Reader input, final IniHandler handler) throws IOException, InvalidIniFormatException
84      {
85          class XmlToIni extends DefaultHandler
86          {
87              private static final String TAG_SECTION = "section";
88              private static final String TAG_OPTION = "option";
89              private static final String TAG_INI = "ini";
90              private static final String ATTR_KEY = "key";
91              private static final String ATTR_VALUE = "value";
92              private static final String ATTR_VERSION = "version";
93              private static final String CURRENT_VERSION = "1.0";
94  
95              @Override public void startElement(String uri, String localName, String qname, Attributes attrs) throws SAXException
96              {
97                  String key = attrs.getValue(ATTR_KEY);
98  
99                  if (qname.equals(TAG_INI))
100                 {
101                     String ver = attrs.getValue(ATTR_VERSION);
102 
103                     if ((ver == null) || !ver.equals(CURRENT_VERSION))
104                     {
105                         throw new SAXException("Missing or invalid 'version' attribute");
106                     }
107 
108                     handler.startIni();
109                 }
110                 else
111                 {
112                     if (key == null)
113                     {
114                         throw new SAXException("missing '" + ATTR_KEY + "' attribute");
115                     }
116 
117                     if (qname.equals(TAG_SECTION))
118                     {
119                         handler.startSection(key);
120                     }
121                     else if (qname.equals(TAG_OPTION))
122                     {
123                         handler.handleOption(key, attrs.getValue(ATTR_VALUE));
124                     }
125                     else
126                     {
127                         throw new SAXException("Invalid element: " + qname);
128                     }
129                 }
130             }
131 
132             @Override public void endElement(String uri, String localName, String qname) throws SAXException
133             {
134                 if (qname.equals(TAG_SECTION))
135                 {
136                     handler.endSection();
137                 }
138                 else if (qname.equals(TAG_INI))
139                 {
140                     handler.endIni();
141                 }
142             }
143         }
144 
145         XmlToIni xmlToini = new XmlToIni();
146 
147         try
148         {
149             SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(input), xmlToini);
150         }
151         catch (Exception x)
152         {
153             throw new InvalidIniFormatException(x);
154         }
155     }
156 
157     public void parseXML(URL input, IniHandler handler) throws IOException, InvalidIniFormatException
158     {
159         parseXML(input.openStream(), handler);
160     }
161 
162     private String parseSectionLine(String line, IniSource source, IniHandler handler) throws InvalidIniFormatException
163     {
164         String sectionName;
165 
166         if (line.charAt(line.length() - 1) != SECTION_END)
167         {
168             parseError(line, source.getLineNumber());
169         }
170 
171         sectionName = unescape(line.substring(1, line.length() - 1).trim());
172         if ((sectionName.length() == 0) && !getConfig().isUnnamedSection())
173         {
174             parseError(line, source.getLineNumber());
175         }
176 
177         if (getConfig().isLowerCaseSection())
178         {
179             sectionName = sectionName.toLowerCase(Locale.getDefault());
180         }
181 
182         handler.startSection(sectionName);
183 
184         return sectionName;
185     }
186 
187     private void parse(IniSource source, IniHandler handler) throws IOException, InvalidIniFormatException
188     {
189         handler.startIni();
190         String sectionName = null;
191 
192         for (String line = source.readLine(); line != null; line = source.readLine())
193         {
194 
195             if (line.charAt(0) == SECTION_BEGIN)
196             {
197                 if (sectionName != null)
198                 {
199                     handler.endSection();
200                 }
201 
202                 sectionName = parseSectionLine(line, source, handler);
203 
204             }
205             else
206             {
207                 if (sectionName == null)
208                 {
209                     if (getConfig().isGlobalSection())
210                     {
211                         sectionName = getConfig().getGlobalSectionName();
212                         handler.startSection(sectionName);
213                     }
214                     else
215                     {
216                         parseError(line, source.getLineNumber());
217                     }
218                 }
219 
220                 parseOptionLine(line, handler, source.getLineNumber());
221 
222             }
223         }
224 
225         if (sectionName != null)
226         {
227             handler.endSection();
228         }
229 
230         handler.endIni();
231     }
232 }