001/*
002 * Copyright 2005,2009 Ivan SZKIBA
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 */
016package org.ini4j.spi;
017
018import org.ini4j.Config;
019import org.ini4j.InvalidFileFormatException;
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.Reader;
024
025import java.net.URL;
026
027import java.util.Locale;
028
029public class IniParser extends AbstractParser
030{
031    private static final String COMMENTS = ";#";
032    private static final String OPERATORS = ":=";
033    static final char SECTION_BEGIN = '[';
034    static final char SECTION_END = ']';
035
036    public IniParser()
037    {
038        super(OPERATORS, COMMENTS);
039    }
040
041    public static IniParser newInstance()
042    {
043        return ServiceFinder.findService(IniParser.class);
044    }
045
046    public static IniParser newInstance(Config config)
047    {
048        IniParser instance = newInstance();
049
050        instance.setConfig(config);
051
052        return instance;
053    }
054
055    public void parse(InputStream input, IniHandler handler) throws IOException, InvalidFileFormatException
056    {
057        parse(newIniSource(input, handler), handler);
058    }
059
060    public void parse(Reader input, IniHandler handler) throws IOException, InvalidFileFormatException
061    {
062        parse(newIniSource(input, handler), handler);
063    }
064
065    public void parse(URL input, IniHandler handler) throws IOException, InvalidFileFormatException
066    {
067        parse(newIniSource(input, handler), handler);
068    }
069
070    private void parse(IniSource source, IniHandler handler) throws IOException, InvalidFileFormatException
071    {
072        handler.startIni();
073        String sectionName = null;
074
075        for (String line = source.readLine(); line != null; line = source.readLine())
076        {
077            if (line.charAt(0) == SECTION_BEGIN)
078            {
079                if (sectionName != null)
080                {
081                    handler.endSection();
082                }
083
084                sectionName = parseSectionLine(line, source, handler);
085            }
086            else
087            {
088                if (sectionName == null)
089                {
090                    if (getConfig().isGlobalSection())
091                    {
092                        sectionName = getConfig().getGlobalSectionName();
093                        handler.startSection(sectionName);
094                    }
095                    else
096                    {
097                        parseError(line, source.getLineNumber());
098                    }
099                }
100
101                parseOptionLine(line, handler, source.getLineNumber());
102            }
103        }
104
105        if (sectionName != null)
106        {
107            handler.endSection();
108        }
109
110        handler.endIni();
111    }
112
113    private String parseSectionLine(String line, IniSource source, IniHandler handler) throws InvalidFileFormatException
114    {
115        String sectionName;
116
117        if (line.charAt(line.length() - 1) != SECTION_END)
118        {
119            parseError(line, source.getLineNumber());
120        }
121
122        sectionName = unescapeFilter(line.substring(1, line.length() - 1).trim());
123        if ((sectionName.length() == 0) && !getConfig().isUnnamedSection())
124        {
125            parseError(line, source.getLineNumber());
126        }
127
128        if (getConfig().isLowerCaseSection())
129        {
130            sectionName = sectionName.toLowerCase(Locale.getDefault());
131        }
132
133        handler.startSection(sectionName);
134
135        return sectionName;
136    }
137}