1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 }