+package mir.util;\r
+\r
+import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
+import java.io.LineNumberReader;\r
+import java.io.OutputStream;\r
+import java.io.*;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Vector;\r
+\r
+import multex.Exc;\r
+import multex.Failure;\r
+\r
+public class PropertiesManipulator {\r
+ private List entries;\r
+ private Map values;\r
+\r
+ public PropertiesManipulator() {\r
+ entries = new Vector();\r
+ values = new HashMap();\r
+ }\r
+\r
+ public void addEmptyLine() {\r
+ entries.add(new EmptyLine());\r
+ }\r
+\r
+ public void addComment(String aComment) {\r
+ entries.add(new Comment(aComment));\r
+ }\r
+\r
+ public void addEntry(String aKey, String aValue) {\r
+ entries.add(new Entry(aKey, aValue));\r
+ values.put(aKey, aValue);\r
+ }\r
+\r
+ public Iterator getEntries() {\r
+ return entries.iterator();\r
+ }\r
+\r
+ public String get(String aKey) {\r
+ return (String) values.get(aKey);\r
+ }\r
+\r
+ public static class Comment {\r
+ private String comment;\r
+\r
+ public Comment(String aComment) {\r
+ comment = aComment;\r
+ }\r
+\r
+ public String getComment() {\r
+ return comment;\r
+ }\r
+ }\r
+\r
+ public static class EmptyLine {\r
+ public EmptyLine() {\r
+ }\r
+ }\r
+\r
+ public static class Entry {\r
+ private String key;\r
+ private String value;\r
+\r
+ public Entry(String aKey, String aValue) {\r
+ key = aKey;\r
+ value = aValue;\r
+ }\r
+\r
+ public String getKey() {\r
+ return key;\r
+ }\r
+\r
+ public String getValue() {\r
+ return value;\r
+ }\r
+ }\r
+\r
+ private final static String PLAIN= "[^\\\\]*";\r
+ private final static String ESCAPE= "\\\\[ tn]";\r
+ private final static String UNICODE= "\\\\u[a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]";\r
+\r
+\r
+ private static String decode(String aValue) {\r
+ try {\r
+ SimpleParser parser = new SimpleParser(aValue);\r
+ StringBuffer result = new StringBuffer();\r
+\r
+ while (!parser.isAtEnd()) {\r
+ result.append(parser.parse(PLAIN));\r
+\r
+ if (!parser.isAtEnd()) {\r
+ if (parser.parses(UNICODE)) {\r
+ String unicode = parser.parse(UNICODE);\r
+\r
+ result.append((char) Integer.parseInt(unicode.substring(2,6), 16));\r
+ }\r
+ else if (parser.parses(ESCAPE)) {\r
+ String escape = parser.parse(ESCAPE);\r
+ result.append(escape.substring(1));\r
+ }\r
+ else\r
+ throw new PropertiesManipulatorExc("Invalid escape code: " + parser.remainingData());\r
+ }\r
+ }\r
+\r
+ return result.toString();\r
+ }\r
+ catch (Throwable t) {\r
+ throw new PropertiesManipulatorFailure(t);\r
+ }\r
+ }\r
+\r
+ private static String encode(String aValue) {\r
+ try {\r
+ StringBuffer result = new StringBuffer();\r
+ boolean leadingspace=true;\r
+\r
+ for (int i = 0; i<aValue.length(); i++) {\r
+ char c = aValue.charAt(i);\r
+\r
+ if (c<0x20 || c>0x7e) {\r
+ String code=Integer.toHexString(c);\r
+ result.append("\\u");\r
+ for (int j=0; j<4-code.length(); j++)\r
+ result.append("0");\r
+ result.append(code);\r
+ }\r
+ else if (c=='\\')\r
+ {\r
+ result.append("\\\\");\r
+ }\r
+ else if (c=='\n')\r
+ {\r
+ result.append("\\n");\r
+ }\r
+ else if (c=='\r')\r
+ {\r
+ result.append("\\r");\r
+ }\r
+ else if (c=='\t')\r
+ {\r
+ result.append("\\t");\r
+ }\r
+ else if (c==' ' && leadingspace) {\r
+ result.append("\\ ");\r
+ }\r
+ else {\r
+ result.append(c);\r
+ }\r
+\r
+ leadingspace = leadingspace && c ==' ';\r
+ }\r
+\r
+ return result.toString();\r
+ }\r
+ catch (Throwable t) {\r
+ throw new PropertiesManipulatorFailure(t);\r
+ }\r
+ }\r
+\r
+ // ML: to be fixed\r
+ private final static String SPACE = "[\t\n\r ]*";\r
+ private final static String KEY = "(([\\\\].)|([^\\\\=: \t\n\r]))*";\r
+ private final static String SEPARATOR = "[\t\n\r ]*[:=]?[\t\n\r ]*";\r
+ private final static String VALUE = "(([\\\\].)|([^\\\\]))*";\r
+\r
+ public static PropertiesManipulator readProperties(InputStream anInputStream) throws PropertiesManipulatorExc, PropertiesManipulatorFailure {\r
+ try {\r
+ PropertiesManipulator result = new PropertiesManipulator();\r
+ LineNumberReader reader = new LineNumberReader(new InputStreamReader(anInputStream, "ISO-8859-1"));\r
+\r
+ String line = reader.readLine();\r
+\r
+ while (line != null) {\r
+ String trimmedLine = line.trim();\r
+\r
+ if (trimmedLine.length() == 0) {\r
+ result.addEmptyLine();\r
+ }\r
+ else if (trimmedLine.startsWith("!") || trimmedLine.startsWith("#")) {\r
+ result.addComment(line);\r
+ }\r
+ else {\r
+ SimpleParser parser = new SimpleParser(line);\r
+ parser.skip(SPACE);\r
+ String key = parser.parse(KEY);\r
+ parser.skip(SEPARATOR);\r
+ String value = parser.parse(VALUE);\r
+ while (parser.remainingData().length()>0) {\r
+ if (!parser.remainingData().equals("\\"))\r
+ throw new PropertiesManipulatorExc("internal error: remainingData = " + parser.remainingData());\r
+\r
+ line = reader.readLine();\r
+ if (line==null) {\r
+ throw new PropertiesManipulatorExc("Unexpected end of file");\r
+ }\r
+ parser = new SimpleParser(line);\r
+ parser.skip(SPACE);\r
+ value = value + parser.parse(VALUE);\r
+ }\r
+\r
+ result.addEntry(decode(key), decode(value));\r
+ }\r
+ line = reader.readLine();\r
+ }\r
+\r
+ reader.close();\r
+\r
+ return result;\r
+ }\r
+ catch (PropertiesManipulatorExc t) {\r
+ throw t;\r
+ }\r
+ catch (Throwable t) {\r
+ throw new PropertiesManipulatorFailure(t);\r
+ }\r
+ }\r
+\r
+ public static void writeProperties(PropertiesManipulator aProperties, OutputStream anOutputStream) throws PropertiesManipulatorExc, PropertiesManipulatorFailure {\r
+ try {\r
+ PrintWriter p = new PrintWriter(new OutputStreamWriter(anOutputStream, "ISO-8859-1"));\r
+\r
+ try {\r
+ Iterator i = aProperties.getEntries();\r
+\r
+ while (i.hasNext()) {\r
+ Object entry = i.next();\r
+\r
+ if (entry instanceof EmptyLine) {\r
+ p.println();\r
+ }\r
+ else if (entry instanceof Comment) {\r
+ p.println(((Comment) entry).getComment());\r
+ }\r
+ else if (entry instanceof Entry) {\r
+ String key = encode( ( (Entry) entry).getKey());\r
+ String value = "";\r
+ if ( ( (Entry) entry).getValue() != null)\r
+ value = encode( ( (Entry) entry).getValue());\r
+\r
+ String line = key + " = " + value;\r
+\r
+ p.println(line);\r
+\r
+ }\r
+ else throw new PropertiesManipulatorExc("Unknown entry class: " +entry.getClass().getName());\r
+ }\r
+ }\r
+ finally {\r
+ p.close();\r
+ }\r
+ }\r
+ catch (Throwable t) {\r
+ throw new PropertiesManipulatorFailure(t);\r
+ }\r
+ }\r
+\r
+ public static class PropertiesManipulatorFailure extends Failure {\r
+ public PropertiesManipulatorFailure(Throwable aThrowable) {\r
+ super(aThrowable.getMessage(), aThrowable);\r
+ }\r
+\r
+ public PropertiesManipulatorFailure(String aMessage, Throwable aThrowable) {\r
+ super(aMessage, aThrowable);\r
+ }\r
+ }\r
+\r
+ public static class PropertiesManipulatorExc extends Exc {\r
+ public PropertiesManipulatorExc(String aMessage) {\r
+ super(aMessage);\r
+ }\r
+ }\r
+}
\ No newline at end of file