org.crosswire.common.util

## Class Ini

- java.lang.Object
- - org.crosswire.common.util.Ini

-     final class Ini
      extends Object

  A utility class for loading an INI style, Multimap configuration file.

  SWORD defines a conf as an INI file with one or more sections. Originally, all modules were described in a single conf, but now each module has its own conf.

  SWORD will be using a single conf to hold overrides for many modules. This is the motivation for this class as opposed to allowing only a single section as `IniSection`.

  Since the most common use case is for a single section, this implementation has an API for delegating to the first IniSection.

  This implementation allows for:
  - Case Insensitive -- Section names, keys and values are case insensitive.
  - Comments -- ; and # preceded only by white space indicate that a line is a comment. Note: SWORD does not support ; but it is present in some 3rd Party repositories such as IBT.
  - Multiple Values -- Each key can have one or more values.
  - Order -- Order of sections, keys and values are retained
  This implementation does not allow for:
  - Globals -- (key,value) pairs before the first section.
  - Quoted Values -- Values surrounded by "" or ''. If present they are part of the value.
  - Retaining comments -- Comments are ignored.
  - Comments after content -- Comments are on lines to themselves.
  - : -- as an alternative for =.
  - nulls -- null values.
  Author:
    DM Smith
  See Also:
    `The GNU Lesser General Public License for details.
    `

- - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `private List<String>` | `list` Indexed list of sections maintaining insertion order.
    `private static org.slf4j.Logger` | `LOGGER` The log stream
    `private static int` | `MAX_BUFF_SIZE` Buffer size is based on file size but keep it with within reasonable limits
    `private Map<String,IniSection>` | `sectionMap` A map of sections by section names.

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `Ini()` Create an empty INI Config.

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `boolean` | `add(String sectionName, String key, String value)` Add a key/value pair to a section.
    `boolean` | `addValue(String key, String value)` Add a value for the key.
    `private String` | `advance(BufferedReader bin)` Get the next line from the input
    `void` | `clear()` Start over.
    `private IniSection` | `doGetSection(String sectionName)`
    `private void` | `doLoad(Reader in)`
    `Collection<String>` | `getKeys()` Get the unmodifiable set of keys of the first section.
    `private IniSection` | `getOrCreateSection(String sectionName)` Get a section, creating it if necessary.
    `IniSection` | `getSection()` Get the first section.
    `String` | `getSectionName()` Get the name of the first section.
    `String` | `getSectionName(int index)`
    `List<String>` | `getSections()` Get an unmodifiable collection of the sections in this INI.
    `private int` | `getSplitPos(String line)` Does this line of text represent a key/value pair?
    `String` | `getValue(String key)` Get the first value for the key in the first section.
    `String` | `getValue(String key, int index)` Get the value for the key specified by the index for the first section.
    `String` | `getValue(String sectionName, String key)` Get the first value for the key specified by the index and the section.
    `String` | `getValue(String sectionName, String key, int index)` Get the value for the key specified by the index and the section.
    `Collection<String>` | `getValues(String key)` Get the values of a key of the first section.
    `int` | `getValueSize(String key)` Get the number of values for a key in the first section
    `int` | `getValueSize(String sectionName, String key)`
    `private boolean` | `isCommentLine(String line)` Determine if the given line is a blank or a comment line.
    `private boolean` | `isSectionLine(String line)` Is this line a [section]?
    `void` | `load(byte[] buffer, String encoding)` Load the conf from a buffer.
    `void` | `load(File file, String encoding)` Load the INI from a file using the given encoding.
    `void` | `load(InputStream is, String encoding)`
    `private String` | `more(BufferedReader bin, String value)` Get continuation lines, if any.
    `private static boolean` | `more(String line)` Is there more following this line
    `boolean` | `remove(String sectionName, String key)` Remove the key if present.
    `boolean` | `remove(String sectionName, String key, String value)` Remove the value if present.
    `boolean` | `removeValue(String key)` Remove the key if present.
    `boolean` | `removeValue(String key, String value)` Remove the value if present in the first section.
    `boolean` | `replace(String sectionName, String key, String value)` Replace a value for a key.
    `boolean` | `replaceValue(String key, String value)` Replace a value for a key.
    `void` | `save(File file, String encoding)` Save the INI to a file using the given encoding.
    `private void` | `save(Writer out)` Output the Ini to the given Writer.
    `int` | `size()` Get the number of sections

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Field Detail

    - #### sectionMap

          private Map<String,IniSection> sectionMap

      A map of sections by section names.

    - #### list

          private List<String> list

      Indexed list of sections maintaining insertion order.

    - #### MAX_BUFF_SIZE

          private static final int MAX_BUFF_SIZE

      Buffer size is based on file size but keep it with within reasonable limits
      See Also:
        Constant Field Values

    - #### LOGGER

          private static final org.slf4j.Logger LOGGER

      The log stream

  - ### Constructor Detail

    - #### Ini

          Ini()

      Create an empty INI Config.

  - ### Method Detail

    - #### clear

          public void clear()

      Start over.

    - #### size

          public int size()

      Get the number of sections
      Returns:
        the number of known sections

    - #### getSections

          public List<String> getSections()

      Get an unmodifiable collection of the sections in this INI.
      Returns:
        the ordered section names

    - #### getSectionName

          public String getSectionName(int index)

    - #### getSectionName

          public String getSectionName()

      Get the name of the first section.
      Returns:
        the name of the first section or null if there are no sections
      Throws:
        `ArrayIndexOutOfBoundsException` - if there are no sections

    - #### getValueSize

          public int getValueSize(String sectionName,
                         String key)

    - #### getValueSize

          public int getValueSize(String key)

      Get the number of values for a key in the first section
      Parameters:
        `key` - the key
      Returns:
        the number of values for a key in the first section

    - #### getValue

          public String getValue(String sectionName,
                        String key,
                        int index)

      Get the value for the key specified by the index and the section.
      Parameters:
        `sectionName` - the name of the section
        `key` - the key for the section
        `index` - the index in the list of values
      Returns:
        the value at the specified index
      Throws:
        `ArrayIndexOutOfBoundsException` - when the index is out of bounds

    - #### getValue

          public String getValue(String sectionName,
                        String key)

      Get the first value for the key specified by the index and the section.
      Parameters:
        `sectionName` - the name of the section
        `key` - the key for the section
      Returns:
        the value at the specified index
      Throws:
        `ArrayIndexOutOfBoundsException` - when the index is out of bounds

    - #### getValue

          public String getValue(String key,
                        int index)

      Get the value for the key specified by the index for the first section.
      Parameters:
        `key` - the key
        `index` - the index
      Returns:
        the value at the specified index
      Throws:
        `ArrayIndexOutOfBoundsException` - when the index is out of bounds

    - #### getValue

          public String getValue(String key)

      Get the first value for the key in the first section.
      Parameters:
        `key` - the key
      Returns:
        the value at the specified index
      Throws:
        `ArrayIndexOutOfBoundsException` - when the index is out of bounds

    - #### add

          public boolean add(String sectionName,
                    String key,
                    String value)

      Add a key/value pair to a section. If the section does not exist, it is created. A null for key or value is not allowed. An empty string for a key is not allowed.
      Parameters:
        `sectionName` - the name of the section
        `key` - the key for the section
        `value` - the value for the key
      Returns:
        `true` if the element was added or already was present

    - #### replace

          public boolean replace(String sectionName,
                        String key,
                        String value)

      Replace a value for a key. A null for key or value is not allowed. An empty string for a key is not allowed.
      Parameters:
        `sectionName` - the name of the section
        `key` - the key for the section
        `value` - the value for the key
      Returns:
        `true` if the element was added or already was present

    - #### remove

          public boolean remove(String sectionName,
                       String key,
                       String value)

      Remove the value if present. If it were the last value for the key, the key is removed. If it were the last key, the section is removed.
      Parameters:
        `sectionName` - the name of the section
        `key` - the key for the section
        `value` - the value for the key
      Returns:
        whether the value was present and removed

    - #### remove

          public boolean remove(String sectionName,
                       String key)

      Remove the key if present. If it were the last key for the section, the section is removed.
      Parameters:
        `sectionName` - the name of the section
        `key` - the key for the section
      Returns:
        whether the key was present and removed

    - #### getSection

          public IniSection getSection()

      Get the first section.
      Returns:
        the first section or null if there are no sections

    - #### getKeys

          public Collection<String> getKeys()

      Get the unmodifiable set of keys of the first section. The set has insertion order.
      Returns:
        the keys of the first section

    - #### getValues

          public Collection<String> getValues(String key)

      Get the values of a key of the first section. The collection has insertion order. Note many keys only have one value. A key that has no values returns null.
      Parameters:
        `key` - the key
      Returns:
        the keyed values or null if the key doesn't exist

    - #### addValue

          public boolean addValue(String key,
                         String value)

      Add a value for the key. Duplicate values are not allowed.
      Parameters:
        `key` - the key for the section
        `value` - the value for the key
      Returns:
        whether the value was added or is already present.

    - #### removeValue

          public boolean removeValue(String key,
                            String value)

      Remove the value if present in the first section. If it were the last value for the key, the key is removed. If it were the last key, the section is removed.
      Parameters:
        `key` - the key for the section
        `value` - the value for the key
      Returns:
        whether the value was present and removed

    - #### removeValue

          public boolean removeValue(String key)

      Remove the key if present. If it were the last key for the section, the section is removed.
      Parameters:
        `key` - the key for the section
      Returns:
        whether the key was present and removed

    - #### replaceValue

          public boolean replaceValue(String key,
                             String value)

      Replace a value for a key. A null for key or value is not allowed. An empty string for a key is not allowed.
      Parameters:
        `key` - the key for the section
        `value` - the value for the key
      Returns:
        `true` if the element was added or already was present

    - #### load

          public void load(InputStream is,
                  String encoding)
                    throws IOException

      Throws:
        `IOException`

    - #### load

          public void load(File file,
                  String encoding)
                    throws IOException

      Load the INI from a file using the given encoding.
      Parameters:
        `file` - the file to load
        `encoding` - the encoding of the file
      Throws:
        `IOException`

    - #### load

          public void load(byte[] buffer,
                  String encoding)
                    throws IOException

      Load the conf from a buffer. This is used to load conf entries from the mods.d.tar.gz file.
      Parameters:
        `buffer` - the buffer to load
        `encoding` - the character encoding for this INI
      Throws:
        `IOException`

    - #### save

          public void save(File file,
                  String encoding)
                    throws IOException

      Save the INI to a file using the given encoding.
      Parameters:
        `file` - the file to load
        `encoding` - the encoding of the file
      Throws:
        `IOException`

    - #### save

          private void save(Writer out)

      Output the Ini to the given Writer.
      Parameters:
        `out` - the Writer to which this Ini should be written

    - #### doGetSection

          private IniSection doGetSection(String sectionName)

    - #### getOrCreateSection

          private IniSection getOrCreateSection(String sectionName)

      Get a section, creating it if necessary.
      Parameters:
        `sectionName` -
      Returns:
        the found or created section

    - #### doLoad

          private void doLoad(Reader in)
                       throws IOException

      Throws:
        `IOException`

    - #### advance

          private String advance(BufferedReader bin)
                          throws IOException

      Get the next line from the input
      Parameters:
        `bin` - The reader to get data from
      Returns:
        the next line or null if there is nothing more
      Throws:
        `IOException` - if encountered

    - #### isCommentLine

          private boolean isCommentLine(String line)

      Determine if the given line is a blank or a comment line.
      Parameters:
        `line` - The line to check.
      Returns:
        true if the line is empty or starts with one of the comment characters

    - #### isSectionLine

          private boolean isSectionLine(String line)

      Is this line a [section]?
      Parameters:
        `line` - The line to check.
      Returns:
        true if the line designates a section

    - #### getSplitPos

          private int getSplitPos(String line)

      Does this line of text represent a key/value pair?
      Parameters:
        `line` - The line to check.
      Returns:
        the position of the split position or -1

    - #### more

          private String more(BufferedReader bin,
                    String value)
                       throws IOException

      Get continuation lines, if any.
      Throws:
        `IOException`

    - #### more

          private static boolean more(String line)

      Is there more following this line
      Parameters:
        `line` - the trimmed string to check
      Returns:
        whether this line continues