Currently showing src/net/jtank/io/Ini.java
/*
 * Copyright (c) 2002-2003, William Denniss
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright 
 *       notice, this list of conditions and the following disclaimer in the 
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Tank Software nor the names of its 
 *       contributors may be used to endorse or promote products derived from 
 *       this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package net.jtank.io;

import java.util.*;
import java.io.*;

/**
 * <p>Ini reading package that can read the common Ini file format.
 * The Ini file format is a text format which is divided into sections
 * and attributes.  Each section can have many attributes however they must
 * have unique names, likewise an Ini can have many
 * sections but they too must have unique names.  In situtations were a list
 * is needed, using the multiline attribute (see below) or a different file
 * format such as XML is recommended.</p>
 *
 * The ini file looks like this:
 * <pre>
 * [ASection]
 * attributevalue=false
 * list=Number2
 * text={
 * Some random text
 * }
 * 
 * [AnotherSection]
 * morevalues=yes
 *
 * </pre>
 *
 * @author William Denniss
 * @version 2.3, 12th October 2003
 */
public class Ini {
	
	
	private String iniName ="";
	
	private Map sections = new HashMap();
	
	/**
	 * Creates an empty Ini.
	 */
	public Ini () {
	}

	/**
	 * Creates an empty Ini file with a recorded iniName.
	 * Note this doesn't load any data from that iniName.
	 *
	 * @see #readIni(BufferedReader)
	 */
	public Ini (String iniName) {
		this.iniName = iniName;
	}
	
	/**
	 * Returns the subsection with the given title
	 *
	 * @param title The name of the subsection to retrieve.
	 * @return The subsection with the passed title
	 */
	public IniSection getSection (String title) {
		return (IniSection) sections.get(title);
	}
	
	/**
	 * Adds a section to an Ini file.
	 */
	public void addSection (IniSection iniSub) {
		sections.put(iniSub.getTitle(), iniSub);
		
	}
	
	/**
	 * Gets the name of this Ini. 
	 *
	 * @return the name of this ini.
	 */
	public String getName () {
		return iniName;
	}
	
	/**
	 * Sets the name of this Ini
	 *
	 * @param iniName the new name of this Ini
	 */
	public void setName (String iniName) {
		this.iniName = iniName;
	}
	
	/**
	 * Helper to set an attribute.  One can also do this by using getSection(String name) and
	 * setAttribute.  If no section exits a new one will be created.
	 *
	 * @param section The name of the subsection.
	 * @param key The attribute key
	 * @param value the value to set the key.
	 */
	public void setSectionAttribute (String section, String key, String value) {
		IniSection sub = getSection(section);
		if (sub == null) {
			sub = new IniSection(section);
			addSection(sub);
		}
		
		sub.setAttribute(key, value);
	}
	
	/**
	 * Helper to get an attribute value.  One can also do this with getSection and getAttribute.
	 *
	 * @param section The name of the section
	 * @param key The name of the attribute key
	 * @return The value of the given attribute or null if the attribute or section doesn't exist
	 */
	public String getSectionAttribute (String section, String key) {
		IniSection sub = getSection(section);
		if (sub == null)
			return null;
		
		return sub.getAttribute(key);
	}
	
	/**
	 * Like getSectionAttribute except that instead of returning null if the section or 
	 * attribute does not exist, it returns the default and casts the value as a boolean.
	 *
	 * @param section The name of the section
	 * @param key The name of the attribute key
	 * @param def The default value for this attribute
	 * @return the boolean value of the given attribute
	 */
	public boolean getSectionAttributeBool (String section, String key, boolean def) {
		IniSection sub = getSection(section);
		if (sub == null)
			return def;
		return sub.getAttribute(key, def+"").equalsIgnoreCase("yes") || 
			sub.getAttribute(key, def+"").equalsIgnoreCase("true");
	}

	/**
	 * Like getSectionAttribute except that instead of returning null if the section or 
	 * attribute does not exist, it returns the default.
	 *
	 * @param section The name of the section
	 * @param key The name of the attribute key
	 * @param def The default value for this attribute
	 * @return the String value of the given attribute
	 */
	public String getSectionAttributeStr (String section, String key, String def) {
		IniSection sub = getSection(section);
		if (sub == null)
			return def;
		return sub.getAttribute(key, def);
	}
	
	/**
	 * Like getSectionAttribute except that instead of returning null if the section or 
	 * attribute does not exist (or is not a valid number), it returns the default and casts the value as an int.
	 *
	 * @param section The name of the section
	 * @param key The name of the attribute key
	 * @param def The default value for this attribute
	 * @return the int value of the given attribute
	 */
	public int getSectionAttributeInt (String section, String key, int def) {
		IniSection sub = getSection(section);
		if (sub == null)
			return def;
		try {
			int toReturn = Integer.parseInt(sub.getAttribute(key, def+""));
			return toReturn;
		} catch (NumberFormatException e) {
			return def;
		}
	}
	
		
	/**
	 * String representation of the Ini file.  Used mainly for debugging.
	 *
	 * @return String representation of the Ini file.
	 */
	public String toString () {
		String toReturn = "";
		Object [] values = sections.keySet().toArray();
		
		for (int i = 0; i < values.length; i++) {
			toReturn += getSection((String) values[i]).toString() + "\n";
		}
		
		return toReturn;
	}
	

	/**
	 * Writes the contents of the INI file to the given Writer.
	 * The Writer can be anything from a BufferedWriter, FileWriter,
	 * StringWriter etc.
	 */
	public void writeIni (Writer w) throws IOException {
		w.write(toString());
		w.close();
	}
	
	/**
	 * Parses the data from the Reader into this Ini file. Typically
	 * The BufferedReader would be connected to a file, string
	 * or URL.
	 *
	 * @param br The source of the data.
	 */
	public void readIni (BufferedReader br) throws IOException {
		
		String line = "";
		line = br.readLine();
		
		IniSection csub = null;
		
		String currentComment = "";
		
		while (line != null) {
			
			
			if (line.length() > 0) {
				
				// Creates a new section if found
				if (line.charAt(0) == '[') {
					csub = new IniSection(line.substring(1, line.lastIndexOf("]")));
					csub.setComment(currentComment);
					addSection(csub);
					
					currentComment = "";					
				
				} else {
					
					// Ignores comments
					if (line.charAt(0) == ';' || line.charAt(0) == '#') {
						
						currentComment += line + "\n";
				
					// Reads the key/value pair
					} else {
						
						// extracts the key value parts
						String pKey = line.substring(0, line.indexOf("="));
						String pValue = line.substring(line.indexOf("=")+1);
	
						// Extracts the value, catering for the multi-line {} attribute
						if (pValue.length() > 0) {
							if (pValue.charAt(0) == '{') {
									
								line = br.readLine();
								pValue = "";
								
								boolean end = false;
								if (line.length() != 0) {
									end = line.charAt(0) == '}';
								}
								
								while (!end) {
									
									if (!pValue.equals(""))
										pValue += "\n";
									pValue += line;
									line = br.readLine();
									
									if (line.length() != 0) {
										end = line.charAt(0) == '}';
									}
									
								}
								
									
							}
						}
						
						// Adds the attribute to the current section
						csub.setAttribute(pKey, pValue, currentComment);
						currentComment = "";
					}
				}
				
				

			} else {
				currentComment += "\n";
			}
			
			// reads the next line
			line = br.readLine();
		}
		
	}

}
     

Total 325 Lines of Code.
Source code formatted using showsrc by William Denniss