package clearcut; import java.io.IOException; import java.io.InputStream; import java.io.File; import java.io.FileInputStream; import java.util.HashMap; import java.util.List; import java.util.ArrayList; public class Ini extends HashMap<String, Object> { private static final String INI = "app.ini"; private static String APP = INI; public static final String NO_SECTION = "_NO_SECTION_"; private String path; private Ini() { super(); } public Ini( String path ) throws IniException { this(); try { load( path ); this.path = path; } catch( IOException x ) { throw new IniException( "Issue with "+path, x ); } } public String path() { if( this.path == null ) return null; if( this.path.endsWith( Ini.APP ) ) return this.path.substring( 0, this.path.length() - (1+Ini.APP.length()) ); return this.path; } public static void app( String name ) { Ini.APP = name + "-" + Ini.INI; } public static String app() { return Ini.APP; } /** This is mostly Sun's code from java.util.Properties */ private synchronized void load( String path ) throws IOException { InputStream inStream = null; try { inStream = new FileInputStream( new File( path ) ); char[] convtBuf = new char[1024]; LineReader lr = new LineReader(inStream); int limit; int keyLen; int valueStart; char c; boolean hasSep; boolean precedingBackslash; String section = NO_SECTION; // Before reaching a 'section' in the .ini file (eg. [database]), String lastSection = null; // we are in a section called _NO_SECTION_ List <String []> list = new ArrayList<String[]>(); while ((limit = lr.readLine()) >= 0) { c = 0; keyLen = 0; valueStart = limit; hasSep = false; precedingBackslash = false; while (keyLen < limit) { c = lr.lineBuf[keyLen]; if ((c == '=') && !precedingBackslash) { valueStart = keyLen + 1; hasSep = true; break; } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { valueStart = keyLen + 1; break; } if (c == '\\') precedingBackslash = !precedingBackslash; else precedingBackslash = false; keyLen++; } while (valueStart < limit) { c = lr.lineBuf[valueStart]; if (c != ' ' && c != '\t' && c != '\f') if (!hasSep && (c == '=')) hasSep = true; else break; valueStart++; } String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf); key = key.trim(); String value = ""; // Windows 3.x and Bash shell style comments if( ! key.startsWith( ";" ) && ! key.startsWith( "#" ) ) { if( ( ! hasSep ) && key.startsWith( "[" ) && key.endsWith( "]" ) ) { key = key.substring( 1, key.length() - 1 ); key = key.substring( 0, key.length() ); section = key; } else { value = loadConvert(lr.lineBuf, valueStart, limit-valueStart, convtBuf); if( ! section.equals( lastSection ) ) list = new ArrayList<String[]>(); String [] entry = new String[2]; entry[ 0 ] = key.trim(); entry[ 1 ] = value.trim(); list.add( entry ); put( section, list ); lastSection = section; } } // System.out.println( "section:"+section+" key:"+key+" value:"+value+ " list size:"+list.size() ); } } finally { try { inStream.close(); } catch( Exception x ) { } } } /** From java.util.Properties */ class LineReader { public LineReader(InputStream inStream) { this.inStream = inStream; } byte[] inBuf = new byte[8192]; char[] lineBuf = new char[1024]; int inLimit = 0; int inOff = 0; InputStream inStream; int readLine() throws IOException { int len = 0; char c = 0; boolean skipWhiteSpace = true; boolean isCommentLine = false; boolean isNewLine = true; boolean appendedLineBegin = false; boolean precedingBackslash = false; boolean skipLF = false; while (true) { if (inOff >= inLimit) { inLimit = inStream.read(inBuf); inOff = 0; if (inLimit <= 0) { if (len == 0 || isCommentLine) { return -1; } return len; } } //The line below is equivalent to calling a //ISO8859-1 decoder. c = (char) (0xff & inBuf[inOff++]); if (skipLF) { skipLF = false; if (c == '\n') { continue; } } if (skipWhiteSpace) { if (c == ' ' || c == '\t' || c == '\f') { continue; } if (!appendedLineBegin && (c == '\r' || c == '\n')) { continue; } skipWhiteSpace = false; appendedLineBegin = false; } if (isNewLine) { isNewLine = false; if (c == '#' || c == '!') { isCommentLine = true; continue; } } if (c != '\n' && c != '\r') { lineBuf[len++] = c; if (len == lineBuf.length) { int newLength = lineBuf.length * 2; if (newLength < 0) { newLength = Integer.MAX_VALUE; } char[] buf = new char[newLength]; System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length); lineBuf = buf; } //flip the preceding backslash flag if (c == '\\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } } else { // reached EOL if (isCommentLine || len == 0) { isCommentLine = false; isNewLine = true; skipWhiteSpace = true; len = 0; continue; } if (inOff >= inLimit) { inLimit = inStream.read(inBuf); inOff = 0; if (inLimit <= 0) { return len; } } if (precedingBackslash) { len -= 1; //skip the leading whitespace characters in following line skipWhiteSpace = true; appendedLineBegin = true; precedingBackslash = false; if (c == '\r') { skipLF = true; } } else { return len; } } } } } private String loadConvert (char[] in, int off, int len, char[] convtBuf) { if (convtBuf.length < len) { int newLen = len * 2; if (newLen < 0) { newLen = Integer.MAX_VALUE; } convtBuf = new char[newLen]; } char aChar; char[] out = convtBuf; int outLen = 0; int end = off + len; while (off < end) { aChar = in[off++]; if (aChar == '\\') { aChar = in[off++]; if(aChar == 'u') { // Read the xxxx int value=0; for (int i=0; i<4; i++) { aChar = in[off++]; switch (aChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': value = (value << 4) + aChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': value = (value << 4) + 10 + aChar - 'a'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': value = (value << 4) + 10 + aChar - 'A'; break; default: throw new IllegalArgumentException( "Malformed \\uxxxx encoding."); } } out[outLen++] = (char)value; } else { if (aChar == 't') aChar = '\t'; else if (aChar == 'r') aChar = '\r'; else if (aChar == 'n') aChar = '\n'; else if (aChar == 'f') aChar = '\f'; out[outLen++] = aChar; } } else { out[outLen++] = (char)aChar; } } return new String (out, 0, outLen); } }