/* * 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.*; /** *
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.
* * The ini file looks like this: *
* [ASection]
* attributevalue=false
* list=Number2
* text={
* Some random text
* }
*
* [AnotherSection]
* morevalues=yes
*
*
*
* @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();
}
}
}