001 /* 002 * Copyright 2005 [ini4j] Development Team 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.ini4j; 018 019 import java.io.IOException; 020 import java.io.InputStream; 021 import java.io.InputStreamReader; 022 import java.io.LineNumberReader; 023 import java.io.Reader; 024 import java.net.URL; 025 026 import org.xml.sax.*; 027 import org.xml.sax.helpers.*; 028 import javax.xml.parsers.*; 029 030 public class IniParser 031 { 032 public static final String COMMENTS = ";#"; 033 public static final char OPERATOR = '='; 034 public static final char SECTION_BEGIN = '['; 035 public static final char SECTION_END = ']'; 036 037 public static final String SERVICE_ID = "org.ini4j.IniParser"; 038 public static final String DEFAULT_SERVICE = SERVICE_ID; 039 040 public static IniParser newInstance() 041 { 042 return (IniParser) ServiceFinder.findService(SERVICE_ID, DEFAULT_SERVICE); 043 } 044 045 public void parse(InputStream input, IniHandler handler) throws IOException, InvalidIniFormatException 046 { 047 parse(new InputStreamReader(input), handler); 048 } 049 050 public void parse(Reader input, IniHandler handler) throws IOException, InvalidIniFormatException 051 { 052 LineNumberReader reader = new LineNumberReader(input); 053 054 handler.startIni(); 055 056 String sectionName = null; 057 058 for (String line = reader.readLine(); line != null; line = reader.readLine()) 059 { 060 line = line.trim(); 061 062 if ( (line.length() == 0) || (COMMENTS.indexOf(line.charAt(0)) >= 0)) 063 { 064 continue; 065 } 066 067 if ( line.charAt(0) == SECTION_BEGIN ) 068 { 069 if ( sectionName != null ) 070 { 071 handler.endSection(); 072 } 073 074 if ( line.charAt(line.length()-1) != SECTION_END ) 075 { 076 parseError(line, reader.getLineNumber()); 077 } 078 079 sectionName = unescape(line.substring(1, line.length()-1).trim()); 080 081 if ( sectionName.length() == 0 ) 082 { 083 parseError(line, reader.getLineNumber()); 084 } 085 086 handler.startSection(sectionName); 087 } 088 else 089 { 090 if ( sectionName == null ) 091 { 092 parseError(line, reader.getLineNumber()); 093 } 094 095 int idx = line.indexOf(OPERATOR); 096 097 if ( idx <= 0 ) 098 { 099 parseError(line, reader.getLineNumber()); 100 } 101 102 String name = unescape(line.substring(0, idx)).trim(); 103 String value = unescape(line.substring(idx+1)).trim(); 104 105 if ( name.length() == 0) 106 { 107 parseError(line, reader.getLineNumber()); 108 } 109 110 handler.handleOption(name, value); 111 } 112 } 113 114 if ( sectionName != null ) 115 { 116 handler.endSection(); 117 } 118 119 handler.endIni(); 120 } 121 122 public void parse(URL input, IniHandler handler) throws IOException, InvalidIniFormatException 123 { 124 parse(input.openStream(), handler); 125 } 126 127 public void parseXML(InputStream input, IniHandler handler) throws IOException, InvalidIniFormatException 128 { 129 parseXML(new InputStreamReader(input), handler); 130 } 131 132 public void parseXML(Reader input, final IniHandler handler) throws IOException, InvalidIniFormatException 133 { 134 class XML2Ini extends DefaultHandler 135 { 136 static final String TAG_SECTION = "section"; 137 static final String TAG_OPTION = "option"; 138 static final String TAG_INI = "ini"; 139 static final String ATTR_KEY = "key"; 140 static final String ATTR_VALUE = "value"; 141 static final String ATTR_VERSION = "version"; 142 143 static final String CURRENT_VERSION = "1.0"; 144 145 public void startElement(String uri, String localName, String qname, Attributes attrs) throws SAXException 146 { 147 String key = attrs.getValue(ATTR_KEY); 148 149 if ( qname.equals(TAG_INI) ) 150 { 151 String ver = attrs.getValue(ATTR_VERSION); 152 153 if ( (ver == null) || ! ver.equals(CURRENT_VERSION)) 154 { 155 throw new SAXException("Missing or invalid 'version' attribute"); 156 } 157 } 158 else 159 { 160 if ( key == null ) 161 { 162 throw new SAXException("missing '" + ATTR_KEY + "' attribute"); 163 } 164 165 if ( qname.equals(TAG_SECTION) ) 166 { 167 handler.startSection(key); 168 } 169 else if ( qname.equals(TAG_OPTION) ) 170 { 171 handler.handleOption(key, attrs.getValue(ATTR_VALUE)); 172 } 173 else 174 { 175 throw new SAXException("Invalid element: " + qname); 176 } 177 } 178 } 179 180 public void endElement(String uri, String localName, String qname) throws SAXException 181 { 182 if ( qname.equals(TAG_SECTION) ) 183 { 184 handler.endSection(); 185 } 186 } 187 } 188 189 XML2Ini xml2ini = new XML2Ini(); 190 191 try 192 { 193 SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(input), xml2ini); 194 } 195 catch (Exception x) 196 { 197 throw new InvalidIniFormatException(x); 198 } 199 } 200 201 public void parseXML(URL input, IniHandler handler) throws IOException, InvalidIniFormatException 202 { 203 parseXML(input.openStream(), handler); 204 } 205 206 protected String unescape(String line) 207 { 208 return Convert.unescape(line); 209 } 210 211 protected void parseError(String line, int lineNumber) throws InvalidIniFormatException 212 { 213 throw new InvalidIniFormatException("parse error (at line: " + lineNumber + "): " + line); 214 } 215 }