[Webfunds-commits] java/webfunds/util FormattedFileException.java IniFileReader.java
Ian Grigg
iang@cypherpunks.ai
Thu, 5 Apr 2001 13:50:42 -0400 (AST)
iang 01/04/05 13:50:42
Added: webfunds/util FormattedFileException.java IniFileReader.java
Log:
Copied IniFileReader into util, changed Ex to something generic.
These are generally used in about 4 places, do not belong in ricardian.
(Rest of code will migrate presently.)
Revision Changes Path
1.1 java/webfunds/util/FormattedFileException.java
Index: FormattedFileException.java
===================================================================
/*
* $Id: FormattedFileException.java,v 1.1 2001/04/05 17:50:41 iang Exp $
*
* Copyright (c) 2001 Systemics Inc on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.util;
public class FormattedFileException
extends ExceptionModel
{
/**
* Known Formatted File failure modes detected.
*/
public static final int
CATCH_ALL = 1, // catch all for other errors
FILE_ERROR = 2, // file could not be read
NO_DATA = 3, // not enough contract data
MULTILINE = 4; // multiline not terminated
public static final String[] errors = {
"<not set, old Ex>",
"'miscellaneous error'",
"File Error",
"No Data",
"Multi-line Field Is Not Terminated"
};
/**
* The line number where the error occurred, counting from 0 to n-1,
* if available (-1 is not set).
*/
protected int line = -1;
public int getLine() { return line; }
public String getErrnoString()
{
if (! (0 <= number && number < errors.length) )
return "<invalid: " + number + ">";
String e = errors[number];
return "(" + number + ") " + ((e == null) ? "'unknown'" : e);
}
public String toString()
{
String s = "";
if (number > 0)
s += getErrnoString() + ": ";
s += super.toString();
if (line >= 0)
s += " [line " + line + "]";
return s;
}
public FormattedFileException(String msg)
{
super(UNKNOWN, msg);
}
/**
* line number is set to default of -1
*
* @param num an identified error from public constants above
* @param msg string interpretation
*/
public FormattedFileException(int num, String msg)
{
super(num, msg);
}
/**
* @param num an identified error from public constants above
* @param line where (approximately) it happened in the file
* @param msg string interpretation
*/
public FormattedFileException(int num, int line, String msg)
{
super(num, msg);
this.line = line;
}
}
1.1 java/webfunds/util/IniFileReader.java
Index: IniFileReader.java
===================================================================
/*
* $Id: IniFileReader.java,v 1.1 2001/04/05 17:50:41 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.util;
import java.util.*;
import java.io.*;
/**
* This class handles files in the windows ini format.
* Currently used by SSD and Ricardian Contracts.
*/
public class IniFileReader
{
//----------------------DATA MEMBERS------------------------------
// data Members
private Hashtable indextable; // what is this used for? only put()
private Hashtable sections;
//----------------------CONSTRUCTORS--------------------------------
/**
* Default constructor creates an empty IniFileReader
*
*/
public IniFileReader()
{
startEmpty();
}
protected void startEmpty()
{
sections = new Hashtable();
indextable = new Hashtable();
}
/**
* read a ini formated file and put in the class
* @param iniFileAsByteArray the byte array containing the ini file
* @except FormattedFileException bad multiline or mixed mode eolns.
*/
public IniFileReader(byte[] data)
throws FormattedFileException
{
startEmpty();
addByteArray(data);
}
/**
* Add the contents of an ini-file formated byte array.
* @param data the byte array containing the additional ini file
* @except FormattedFileException bad multiline or mixed mode eolns.
*/
public void addByteArray(byte[] data)
throws FormattedFileException
{
if (data == null || data.length == 0)
return ;
add(data);
}
final static int TRIM_WHITE_SPACE = 3;
protected static String lastErrors = "";
protected static String lastEoln = "";
protected static int numErrors = 0;
public static String getLastErrors() { return lastErrors ; }
public static int getNumErrors() { return numErrors ; }
/**
* Take a byte array and turn it into an array of trimmed lines.
*/
public static String[] toLines(byte[] txt)
{
return toLines(txt, TRIM_WHITE_SPACE);
}
/**
* Take a byte array and turn it into an array of lines.
* A line is terminated by an eoln string, which must be the
* the same throughout the array.
*
* Note. This is used because the semantics are precise, whereas
* the equivalent in java.io.* is unclear, or sufficiently
* murky for the hashing task. Also, the exceptions are boring.
*
* @param If version >= 3 then proper trim is used.
* @except FormattedFileException if mixed eoln strings are found
*/
public static String[] toLines(byte[] txt, int version)
{
numErrors = 0; lastErrors = lastEoln = "";
if (txt == null || txt.length == 0)
return new String[0];
byte[] eoln = null;
Stack stuk = new Stack();
int next = 0;
int lineCount = 0; // for diags only
int total = txt.length;
while (next < total)
{
int q = next;
while (q < total && txt[q] != '\n' && txt[q] != '\r')
q++;
int end = q;
if (version >= TRIM_WHITE_SPACE) // for hash/sig
{
while (end > next && (0<=txt[end-1] && txt[end-1]<='\u0020'))
--end;
// System.err.println(" trimmed " + (q - end) + " chars");
}
// reached the end of line
// System.err.println(" next == " + next + " end == " + end);
String s = new String(txt, next, end - next);
// System.err.println(" <" + s + ">");
stuk.push(s);
lineCount++;
if (q == total) // no last eoln not quite an error, too common
{
lastErrors += " eoln? " + lineCount;
}
else if (eoln == null) // first time, find out what eoln is
{
//
// Need to grab the line terminator, and save it for
// other times.
//
if (txt[q] == '\n') // \n is 'nix
{
eoln = new byte[1];
eoln[0] = (byte)'\n';
lastEoln = "nix";
}
else if (txt[q] == '\r') // \r ...
{
if (q+1 < total && txt[q+1] == '\n') // \r\n is Doze
{
eoln = new byte[2];
eoln[0] = (byte)'\r';
eoln[1] = (byte)'\n';
q++;
lastEoln = "doze";
}
else // just \r is Mac
{
eoln = new byte[1];
eoln[0] = (byte)'\r';
lastEoln = "mac";
}
}
else
throw new RuntimeException("huh? no eoln at " + lineCount);
q++;
}
else
{
//System.err.println("Check ....");
//
// Check it is the same as the first time.
//
int here = q;
boolean ok = true;
for (int i = 0; i < eoln.length; i++)
{
//System.err.println("q " + q + " total " + total + " i == " + i);
//if(q < total) System.err.println("byte is " + txt[q] + " against " + eoln[i]);
if (q >= total || txt[q++] != eoln[i])
{
ok = false;
break ;
}
}
//
// Any change is a bad file, file a complaint.
// Cannot pick up Mac with \r\n in it (sucks \r).
//
if (!ok) // what the hell is it? try all known
{
q = here; // back to the start of the newline
if (eoln.length == 2) // we want Doze, got other
{
if (txt[q] == '\r') // so q+1 != '\n', is Mac
lastErrors += " M" + lineCount;
else // q == \n, is 'nix.
lastErrors += " X" + lineCount;
}
else if (txt[q] == '\r') // is Doze or Mac
{
//System.err.println("q " + q + " total " + total);
//if (q+1 < total) System.err.println("byte is " + txt[q+1]);
if (q+1 < total && txt[q+1] == '\n') // is Doze
{
q++;
lastErrors += " D" + lineCount;
}
else // is Mac
lastErrors += " M" + lineCount;
}
else if (txt[q] == '\n') // is 'nix, not a \r
lastErrors += " X" + lineCount;
else
throw new RuntimeException("cannot handle: " +
txt[q] + txt[q+1] +
" when using " + lastEoln + " line endings");
q++; // always at least one
numErrors++;
}
}
next = q;
}
int len = stuk.size();
String[] lines = new String[len];
while (len-- > 0)
lines[len] = (String)stuk.pop();
return lines;
}
protected static void doLines(String desc, String test)
{
System.err.println(desc + ":");
String[] lines = toLines(test.getBytes());
for (int i = 0; i < lines.length; i++)
System.err.println(" <" + lines[i] + ">");
System.err.println("last eoln == " + lastEoln + "; " +
getNumErrors() + " Errors: " + getLastErrors());
System.err.println();
}
public static void testLines()
{
doLines("empty", "");
doLines("no eoln", "no eoln");
String[] eolns = {"\n", "\r", "\r\n"};
for (int i = 0; i < eolns.length; i++)
{
System.err.println("===== " + i);
String nl = eolns[i];
doLines("lacks end", "one eoln" + nl + "two lines");
doLines("3 lines only", nl + nl + nl);
for (int j = 0; j < eolns.length; j++)
{
if (i == j) continue ;
doLines("mixed " + j, "start" + nl + " change " + eolns[j]);
}
}
}
/**
* Add a files worth to the hashtables.
* @except FormattedFileException if a multiline could not be completed
*/
protected void add(byte[] iniFileAsByteArray)
throws FormattedFileException
{
String[] lines = toLines(iniFileAsByteArray);
//
// Read the file line by line and put data in the right place
//
String line;
String sectionName = null;
int lineNum = 0;
int numLines = lines.length;
while (lineNum < numLines)
{
line = lines[lineNum++];
line.trim();
if (line.length() == 0 ) // Skip blank lines
continue;
if (line.startsWith(";") ) // Skip comment lines
continue;
if(line.startsWith("#") )
continue;
//
// Is it a new section?
//
if (line.startsWith("[") && line.endsWith("]") )
{
// the section should at least contain one or more
// characters
// if (line.length() ==2 )
// get the section out of the tag
// and put it in variable sectionName
// sectionName is used afterwards to add items
// to the section
sectionName = line.substring(1,line.length() -1);
addSection(sectionName);
continue;
}
//
// Or, it could be a vector item.
// A vector item is one where there are many lines of the form:
// key += value1
// key += value2
//
int i = line.indexOf("+=");
if (i != -1 && sectionName != null)
{
String key = line.substring(0,i).trim();
String value= line.substring(i + 2).trim();
Hashtable temp;
// should already be there
temp = (Hashtable) getHashOfSectionItems(sectionName);
Vector vec = (Vector)temp.get(key);
if(vec == null)
vec = new Vector();
vec.addElement(value);
temp.put(key, vec);
continue;
}
//
// Or, it could be an ordinary item.
//
i = line.indexOf('=');
if (i != -1 && sectionName != null)
{
String key = line.substring(0,i).trim();
String value;
//
// If the value starts with ' then this is multi-line.
//
if (line.substring(i+1).startsWith("'"))
{
//remove the starting '
value= line.substring(i + 2);
if (!value.endsWith("'")){
// read until the end of the quotes
//are the end of the quotes on the same line
String temp= null;
while ((temp == null) || (!temp.endsWith("'")))
{
temp = lines[lineNum++];
// temp = bufr.readLine();
//
// Wierd. This needed to be if-else-else,
// all the way through, or it would turn
// empty lines into two empties.
// This bug seems to have always existed.
//
if (temp.length() ==0)
value += "\n";
else if (temp.endsWith("'"))
{
value += temp.substring(0,temp.length()-1) + "\n";
}
else
{
value += temp + "\n";
if (lineNum >= numLines)
throw new FormattedFileException(
FormattedFileException.MULTILINE, lineNum,
"eof reached before end of multiline");
}
}
}
}
//
// If the value starts with * then this is multi-line.
//
else if(line.substring(i+1).trim().equals("*") )
{
if (lineNum + 1 > numLines)
throw new FormattedFileException(
FormattedFileException.MULTILINE, lineNum,
"Too few lines for multiline");
String temp = lines[lineNum++];
if (!temp.equals("{"))
throw new FormattedFileException(
FormattedFileException.MULTILINE, lineNum,
"No { after *");
value = "";
temp = null;
while ( ! (temp = lines[lineNum++]).trim().equals("}") )
{
value += temp + "\n";
if (lineNum >= numLines)
throw new FormattedFileException(
FormattedFileException.MULTILINE, lineNum,
"eof reached before end of multiline");
}
}
//
// Else, just an ordinary value.
//
else
{
value= line.substring(i + 1).trim();
}
//
// Add a key / value pair to the Hashtable of the section.
//
Hashtable temp;
temp = (Hashtable) getWriteHashOfSectionItems(sectionName);
temp.put(key,value);
}
}
}
//----------------------GLOBAL-------------------------------------
/**
*
* @return This method returns a hash of selections<BR>
* The has returned contains more Hashes<BR>
* <UL><LI>
* sections<BR>
* (String sectionName) (Hash of items)<BR>
* <BR>
* (Hash of items)<BR>
* (String item) (String Value)<BR>
* </LI><LI>
* to get the items back explicit cast is needed
* </LI></UL>
*/
public Hashtable getIniFileHash()
{
return sections;
}
/**
* Make a windows ini-file-formatted representation of the data
* @return a byte array of the file
*/
public byte[] saveToByteArray()
throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedWriter bufw = new BufferedWriter( new OutputStreamWriter(baos));
String[] sectionNames = getSectionNames();
Object obj;
for (int i =0 ; i < getNumberOfSections() ; i++)
{
bufw.newLine();
bufw.newLine();
bufw.write("[");
bufw.write(sectionNames[i],0, sectionNames[i].length());
bufw.write("]");
bufw.newLine();
bufw.newLine();
// get all the items in the section
String[] items = getSectionItems(sectionNames[i]);
for (int j=0 ; j < getNumberOfSectionItems(sectionNames[i]);j++)
{
obj = getSectionItemObject(sectionNames[i],items[j]);
if(obj instanceof String)
{
bufw.write(items[j] ,0,items[j].length());
String str = (String)obj;
bufw.write("=");
//hanlde mutlti line
if (str.indexOf("\n") != -1)
bufw.write("'");
bufw.write(str,0,str.length());
if (str.indexOf("\n") != -1)
bufw.write("'");
bufw.newLine();
}
else if (obj instanceof Vector)
{
Vector vec = (Vector)obj;
String str = "";
for(Enumeration e = vec.elements(); e.hasMoreElements();)
{
bufw.write(items[j] ,0,items[j].length());
bufw.write("+=");
str = (String)e.nextElement();
bufw.write(str,0,str.length());
bufw.newLine();
}
}
}
}
bufw.flush();
bufw.close();
return baos.toByteArray();
}
/**
* Save the IniFileReader contect to a file
* @param fileName the file name on wich to save
*/
public void saveToFile (String fileName)
throws IOException
{
byte [] data = saveToByteArray();
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(data);
fos.close();
}
//----------------------SECTIONS-----------------------------------
/**
* this method returns the number of sections in the IniFileReader class
* @return The number of sections
*/
public int getNumberOfSections()
{
return sections.size();
}
/**
*
* @return an array of Strings of the section names
*/
public String[] getSectionNames()
{
String [] ret = new String[getNumberOfSections()];
Enumeration sectionNames = sections.keys();
int counter=0;
while (sectionNames.hasMoreElements() )
{
ret[counter] = (String) sectionNames.nextElement();
counter++;
}
return ret;
}
private static final String none = "(none)";
/**
* This method add a section to the IniFileReader class
* @param sectionName the name of the new section
*/
public void addSection(String sectionName)
{
if (sectionName == null || sectionName.equals(""))
sectionName = none;
if (sections.get(sectionName) != null) // check for duplicates?
return ;
// indextable not used?
indextable.put( sectionName, new Integer(indextable.size() ));
sections.put(sectionName , new Hashtable());
}
/** This method can be used to remove sections in the IniFileReader class
* @param sectionName the name of the section to remove
*/
public void removeSection(String sectionName)
{
if (sectionName == null || sectionName.equals(""))
sectionName = none;
indextable.remove(sectionName);
sections.remove(sectionName);
}
//----------------------SECTION ITEM-----------------------------------
/**
* this is used for getting the amount of items in a section
* of a IniFileReader class
*
* @param section section is an existing section on the ini file
* @return returns the number of items in the section
*/
public int getNumberOfSectionItems( String section )
{
// get the specific section
Hashtable temp = getHashOfSectionItems(section);
if (temp == null) // no section
return 0 ;
return temp.size();
}
/**
* This is used to get a Hashtable of the items in the specific
* section of the IniFileReader class for the purpose of adding
* or setting a new key. On return, there is a hash, even if
* there wasn't one before.
*
* This changes the semantics somewhat - create on demand.
*
* @param section section is an existing section on the ini file
* @return A Hashtable of Items contained in the section
*/
public Hashtable getWriteHashOfSectionItems( String section )
{
if (section == null || section.equals(""))
section = none;
Hashtable hash = (Hashtable)sections.get(section);
if (hash == null)
{
addSection(section);
hash = (Hashtable)sections.get(section);
}
return hash;
}
/**
* This is used to get a Hashtable of the items in the specific
* section of the IniFileReader class
*
* @param section section is an existing section on the ini file
* @return A Hashtable of Items contained in the section, or null if none.
*/
public Hashtable getHashOfSectionItems( String section )
{
Hashtable hash = (Hashtable)sections.get(section);
return hash;
}
/**
* @param section section is an existing section on the ini file
* @return an array of Strings of the items contained by the section
*/
public String[] getSectionItems( String section )
{
Hashtable temp = getHashOfSectionItems(section);
if (temp == null) // no section
return new String[0] ;
Enumeration sectionItemNames = temp.keys();
String[] ret = new String[temp.size()];
int counter=0;
while (sectionItemNames.hasMoreElements() )
{
ret[counter++] = (String)sectionItemNames.nextElement();
}
return ret;
}
public Object getSectionItemObject(String section, String item)
{
Hashtable temp = getHashOfSectionItems(section);
if (temp == null) // no section
return null;
return temp.get(item);
}
/**
* Get an item from a section.
* Also checks for section_item, which is equivalent.
*
* @param section is an existing section in the ini file
* @param item is an existing item in the section in the ini file
* @return A Strings containing the value of the item
*/
public String getSectionItemValue(String section, String item)
{
Hashtable temp = getHashOfSectionItems(section);
if (temp == null) // no section
return (String) null;
//System.err.println("trying for " + section + " + " + item);
if (item == null || item.length() == 0)
return null ;
Object obj = temp.get(item);
if (obj != null)
{
//
// Hack, to allow dump to print stuff out, should be cleaned out.
//
String s;
if (obj instanceof String)
s = (String) obj;
else if (obj instanceof Vector) // shouldn't be called, (dump)
{
Vector v = (Vector) obj;
s = (String) v.firstElement(); // first one is good enough
}
else
throw new RuntimeException("("+obj.getClass().getName()+") " +
obj);
return s ;
}
String prefix = section + "_"; // check for section_item
if (item.length() > prefix.length())
{
String check = item.substring(0, prefix.length());
if (prefix.equals(check))
return null ;
}
item = prefix + item;
//System.err.println("trying for " + section + " + " + item);
return (String) temp.get(item);
}
/**
* This method can be used to add a item/value pair to a section
* if the value is mutliline then you should use
* addMultilineSectionItem
* @param sectionName the name of the section
* @param item the name of the item in the section
* @param value the value of the item
*/
public void addSectionItem(String sectionName, String item, String value)
{
Hashtable temp = getWriteHashOfSectionItems(sectionName);
temp.put (item , value);
}
/**
* This method can be used to add a item/value pair to a section
* using for mutliline
* @param sectionName the name of the section
* @param item the name of the item in the section
* @param value the value of the item
*/
public void addMultilineSectionItem(String sectionName , String item , String value)
{
value = "'" + value + "'";
Hashtable temp = getWriteHashOfSectionItems(sectionName);
temp.put (item , value);
}
/**
* This method can be used to change a value pair of a item in a section
* @param sectionName the name of the section
* @param item the name of the item in the section
* @param value the value of the item
*/
public void changeSectionItemValue(String sect, String item, String value)
{
Hashtable temp = getWriteHashOfSectionItems(sect);
temp.put (item , value);
}
/**
* This method can be used to remove an item form a section
* @param sectionName the name of the section
* @param item the name of the item to remove
*/
public void removeSectionItem(String sectionName, String item)
{
Hashtable temp = getHashOfSectionItems(sectionName);
if (temp == null) // no section
return ;
temp.remove(item);
}
public String[] getSectionItemArray(String sectionName, String item)
{
Hashtable temp = getHashOfSectionItems(sectionName);
if (temp == null) // no section
return new String[0] ;
Object obj = temp.get(item);
if (obj == null)
return new String[0] ;
if (obj instanceof Vector)
{
Vector vec = (Vector)obj;
String[] retval = new String[vec.size() ];
vec.copyInto(retval);
return retval ;
}
else if (obj instanceof String)
{
String[] retval = new String[1];
retval[0] = (String)obj;
return retval ;
}
throw new RuntimeException("bad obj ("+item+"): "+obj.toString());
}
public void removeSectionItemArray(String sectionName, String item, String value)
{
Hashtable temp = getHashOfSectionItems(sectionName);
if (temp == null) // no section
return ;
Vector vec = (Vector)temp.get(item);
if(vec == null)
{
return;
}
vec.removeElement(value);
}
/*
public void dump(OutputStream out)
{
PrintWriter pw = new PrintWriter(out);
Object[][] content = new String[indextable.size()][2];
int index = 0;
String nextElement = "";
for(Enumeration e = indextable.keys(); e.hasMoreElements();)
{
nextElement = e.nextElement().toString();
content[index][0] = nextElement;
content[index++][1] = indextable.get(nextElement).toString();
}
if(content.length > 1)
{
boolean moved;
int curndx=content.length;
do
{
moved=false;
Object temp0 = null;
Object temp1 = null;
for (int index2=1; index2 < curndx; index2++) {
if ( new Integer((String)content[index2][1]).intValue() < new Integer((String)content[index2-1][1]).intValue() )
{
moved = true;
temp0 = content[index2][0];
temp1 = content[index2][1];
content[index2][0] = content[index2-1][0];
content[index2][1] = content[index2-1][1];
content[index2-1][0] = temp0;
content[index2-1][1] = temp1;
}
}
curndx--;
} while (moved);
}
for(int i = 0; i < content.length; i++)
{
String section = (String)content[i][0];
pw.println( ("[" + section + "]" ) );
String[] items = getSectionItems(section);
for (int j=0 ; j < getNumberOfSectionItems(section);j++)
{
pw.print("\t" + items[j]);
pw.println("\t" + getSectionItemValue(section,items[j]) );
}
}
pw.flush();
}
*/
//----------------------TEST CODE-----------------------------------
public void dump()
{
System.err.println("___IniFile Dumping the Ini file___");
//example get the number of sections
System.err.println("Number of sections=" + getNumberOfSections());
// example get a array of section names
String[] sectionNames = getSectionNames();
for (int i =0 ; i < getNumberOfSections() ; i++)
{
System.err.println(sectionNames[i]);
// get all the items in the section
String[] items = getSectionItems(sectionNames[i]);
for (int j=0 ; j < getNumberOfSectionItems(sectionNames[i]);j++)
{
System.err.print("\t" + items[j]);
System.err.println("\t" + getSectionItemValue(sectionNames[i],
items[j]));
}
}
}
/**
* Test method requires a ini file called test.ini
*/
public static void main(String[] arg)
throws IOException, FormattedFileException
{
if (arg.length == 0)
{
System.err.println("Test Usage: IniFileReader [-lines] filename");
System.exit(1);
}
if ("-lines".equals(arg[0]))
{
testLines();
System.exit(0);
}
// test the fileName constuctor
System.err.println("1: using the fileName constructor");
File test = new File(arg[0]);
FileInputStream fis = new FileInputStream(test);
byte[] data = new byte[fis.available()];
fis.read(data);
fis.close();
IniFileReader ini = new IniFileReader(data);
System.err.println("Dumping content");
ini.dump();
// add one section
System.err.println();
System.err.println("3: adding a section to the IniFileReader class");
ini.addSection("addedSection");
ini.dump();
//add one item
System.err.println();
System.err.println("4: adding a item to the IniFileReader class");
ini.addSectionItem("addedSection","addeditem","this is added");
ini.dump();
//change the value of the item
System.err.println();
System.err.println("5: change the value of the item");
ini.addSectionItem("addedSection","addeditem","this is added and has chagned value");
ini.dump();
//remove the item
System.err.println();
System.err.println("6: remove the item");
ini.removeSectionItem("addedSection","addeditem");
ini.dump();
//remove the section
System.err.println();
System.err.println("7: remove the section");
ini.removeSection("addedSection");
ini.dump();
ini.saveToFile("keesj.ini");
}
}