package org.objectstyle.woenvironment.plist; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @SuppressWarnings("all") public class WOLPropertyListSerialization { public static class _Utilities { public static final String ROOT = "root"; private int _lineNumber; private int _startOfLineCharIndex; private static int _savedIndex; private static int _savedLineNumber; private static int _savedStartOfLineCharIndex; private static final int NSToPrecompUnicodeTable[] = { 160, 192, 193, 194, 195, 196, 197, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 217, 218, 219, 220, 221, 222, 181, 215, 247, 169, 161, 162, 163, 8260, 165, 402, 167, 164, 8217, 8220, 171, 8249, 8250, 64257, 64258, 174, 8211, 8224, 8225, 183, 166, 182, 8226, 8218, 8222, 8221, 187, 8230, 8240, 172, 191, 185, 715, 180, 710, 732, 175, 728, 729, 168, 178, 730, 184, 179, 733, 731, 711, 8212, 177, 188, 189, 190, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234, 235, 236, 198, 237, 170, 238, 239, 240, 241, 321, 216, 338, 186, 242, 243, 244, 245, 246, 230, 249, 250, 251, 305, 252, 253, 322, 248, 339, 223, 254, 255, 65533, 65533 }; private void _saveIndexes(int index, int line, int startOfLine) { _savedIndex = index; _savedLineNumber = line; _savedStartOfLineCharIndex = startOfLine; } private String _savedIndexesAsString() { return "line number: " + _savedLineNumber + ", column: " + (_savedIndex - _savedStartOfLineCharIndex); } public static String stringFromPropertyList(Object plist) throws PropertyListParserException { if (plist == null) { return null; } StringBuffer buffer = new StringBuffer(128); _appendObjectToStringBuffer(plist, buffer, 0); return buffer.toString(); } public static Object propertyListWithContentsOfFile(String path, ParserDataStructureFactory factory) throws IOException, PropertyListParserException { String string = WOLPropertyListSerialization.stringFromFile(new File(path)); return propertyListFromString(string, factory); } public static Object propertyListFromString(String string, ParserDataStructureFactory factory) throws PropertyListParserException { return (new _Utilities())._propertyListFromString(string, factory); } private Object _propertyListFromString(String string, ParserDataStructureFactory factory) throws PropertyListParserException { _lineNumber = _startOfLineCharIndex = 0; if (string == null) { return null; } char characters[] = string.toCharArray(); Object objects[] = new Object[1]; _lineNumber = 1; _startOfLineCharIndex = 0; objects[0] = null; int index = 0; index = _readObjectIntoObjectReference(characters, index, objects, WOLPropertyListSerialization._Utilities.ROOT, factory); index = _skipWhitespaceAndComments(characters, index); if (index != -1) { throw new PropertyListParserException("The property list contained an object, but it appears to be truncated (line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + ")."); } return objects[0]; } private static void _appendObjectToStringBuffer(Object object, StringBuffer buffer, int indentionLevel) throws PropertyListParserException { if (object instanceof String) { _appendStringToStringBuffer((String) object, buffer, indentionLevel); } else if (object instanceof StringBuffer) { _appendStringToStringBuffer(((StringBuffer) object).toString(), buffer, indentionLevel); } else if (object instanceof EMMutableData) { _appendDataToStringBuffer((EMMutableData) object, buffer, indentionLevel); } else if (object instanceof List) { _appendCollectionToStringBuffer((List) object, buffer, indentionLevel); } else if (object instanceof Set) { _appendCollectionToStringBuffer((Set) object, buffer, indentionLevel); } else if (object instanceof Map) { _appendDictionaryToStringBuffer((Map) object, buffer, indentionLevel); } else if (object instanceof Boolean) { String value = ((Boolean) object).booleanValue() ? "true" : "false"; _appendStringToStringBuffer(value, buffer, indentionLevel); } else { _appendStringToStringBuffer(object.toString(), buffer, indentionLevel); } } /** * Escapes all doublequotes and backslashes. */ protected static String escapeString(String str) { char[] chars = str.toCharArray(); int len = chars.length; StringBuffer buf = new StringBuffer(len + 3); for (int i = 0; i < chars.length; i++) { if (chars[i] < '\200') { if (chars[i] == '\n') { buf.append("\\n"); continue; } if (chars[i] == '\r') { buf.append("\\r"); continue; } if (chars[i] == '\t') { buf.append("\\t"); continue; } if (chars[i] == '"') { buf.append("\\\""); continue; } if (chars[i] == '\\') { buf.append("\\\\"); continue; } if (chars[i] == '\f') { buf.append("\\f"); continue; } if (chars[i] == '\b') { buf.append("\\b"); continue; } if (chars[i] == '\007') { buf.append("\\a"); continue; } if (chars[i] == '\013') { buf.append("\\v"); } else { buf.append(chars[i]); } } else { char character = chars[i]; byte nibble1 = (byte) (character & 15); character >>= '\004'; byte nibble2 = (byte) (character & 15); character >>= '\004'; byte nibble3 = (byte) (character & 15); character >>= '\004'; byte nibble4 = (byte) (character & 15); character >>= '\004'; buf.append("\\U"); buf.append(_hexDigitForNibble(nibble4)); buf.append(_hexDigitForNibble(nibble3)); buf.append(_hexDigitForNibble(nibble2)); buf.append(_hexDigitForNibble(nibble1)); } } return buf.toString(); } /** * Returns a quoted String, with all the escapes preprocessed. May * return an unquoted String if it contains no special characters. The * rule for a non-special character is the following: * * <pre> * c >= 'a' && c <= 'z' * c >= 'A' && c <= 'Z' * c >= '0' && c <= '9' * c == '_' * c == '$' * c == ':' * c == '.' * c == '/' * </pre> */ private static void _appendStringToStringBuffer(String string, StringBuffer buffer, int indentionLevel) { boolean shouldQuote = false; // scan string for special chars, // if we have them, string must be quoted // String noQuoteExtras = "_$:./"; char[] chars = string.toCharArray(); int len = chars.length; if (len == 0) { shouldQuote = true; } for (int i = 0; !shouldQuote && i < len; i++) { char c = chars[i]; // if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= // '0' && c <= '9') || noQuoteExtras.indexOf(c) >= 0) { if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { continue; } shouldQuote = true; } String escapedStr = escapeString(string); if (shouldQuote) { buffer.append('\"'); buffer.append(escapedStr); buffer.append('\"'); } else { buffer.append(escapedStr); } } private static void _appendDataToStringBuffer(EMMutableData data, StringBuffer buffer, int indentionLevel) { buffer.append('<'); byte bytes[] = data.bytes(); for (int i = 0; i < bytes.length; i++) { byte dataByte = bytes[i]; byte nibble1 = (byte) (dataByte & 15); dataByte >>= 4; byte nibble2 = (byte) (dataByte & 15); buffer.append(_hexDigitForNibble(nibble2)); buffer.append(_hexDigitForNibble(nibble1)); } buffer.append('>'); } private static void _appendCollectionToStringBuffer(Collection collection, StringBuffer buffer, int indentionLevel) throws PropertyListParserException { buffer.append('('); if (!collection.isEmpty()) { int originalLength = buffer.length(); StringBuffer oneLineBuffer = new StringBuffer(78); Iterator iter = collection.iterator(); for (int i = 0; iter.hasNext(); i++) { Object obj = iter.next(); if (obj != null) { if (i > 0) { buffer.append(", "); } buffer.append('\n'); _appendIndentationToStringBuffer(buffer, indentionLevel + 1); int itemStart = buffer.length(); _appendObjectToStringBuffer(obj, buffer, indentionLevel + 1); int itemEnd = buffer.length(); if (oneLineBuffer != null && (oneLineBuffer.length() + (itemEnd - itemStart) < 79)) { if (i > 0) { oneLineBuffer.append(", "); } oneLineBuffer.append(buffer.substring(itemStart, itemEnd)); } else { oneLineBuffer = null; } } } if (oneLineBuffer != null && oneLineBuffer.length() < 78) { buffer.setLength(originalLength); buffer.append(oneLineBuffer); } else { buffer.append('\n'); _appendIndentationToStringBuffer(buffer, indentionLevel); } } buffer.append(')'); } private static void _appendDictionaryToStringBuffer(Map dictionary, StringBuffer buffer, int indentionLevel) throws PropertyListParserException { buffer.append('{'); if (!dictionary.isEmpty()) { int originalLength = buffer.length(); StringBuffer oneLineBuffer = new StringBuffer(78); Iterator keyEnumerator; Set keySet = dictionary.keySet(); ArrayList arrayList = new ArrayList(keySet); try { Collections.sort(arrayList); keyEnumerator = arrayList.iterator(); } catch (Exception e) { keyEnumerator = keySet.iterator(); } while (keyEnumerator.hasNext()) { Object key = keyEnumerator.next(); if (key == null) { throw new PropertyListParserException("Property list generation failed while attempting to write hashtable. Non-String key found in Hashtable. Property list dictionaries must have String's as keys. The attempkey was '" + key + "'."); } else if (!(key instanceof String)) { key = key.toString(); } Object value = dictionary.get(key); if (value != null) { buffer.append('\n'); _appendIndentationToStringBuffer(buffer, indentionLevel + 1); int keyStart = buffer.length(); _appendStringToStringBuffer((String) key, buffer, indentionLevel + 1); int keyEnd = buffer.length(); buffer.append(" = "); int valueStart = buffer.length(); _appendObjectToStringBuffer(value, buffer, indentionLevel + 1); int valueEnd = buffer.length(); buffer.append("; "); if (oneLineBuffer != null && (oneLineBuffer.length() + (keyEnd - keyStart) + (valueEnd - valueStart) < 79)) { oneLineBuffer.append(buffer.substring(keyStart, keyEnd)); oneLineBuffer.append(" = "); oneLineBuffer.append(buffer.substring(valueStart, valueEnd)); oneLineBuffer.append("; "); } else { oneLineBuffer = null; } } } if (oneLineBuffer != null && oneLineBuffer.length() < 78) { buffer.setLength(originalLength); buffer.append(oneLineBuffer); } else { buffer.append('\n'); _appendIndentationToStringBuffer(buffer, indentionLevel); } } buffer.append('}'); } private static void _appendIndentationToStringBuffer(StringBuffer buffer, int indentionLevel) { for (int i = 0; i < indentionLevel; i++) { buffer.append(" "); } } private static final char _hexDigitForNibble(byte nibble) { char digit = '\0'; if (nibble >= 0 && nibble <= 9) { digit = (char) (48 + (char) nibble); } else if (nibble >= 10 && nibble <= 15) { digit = (char) (97 + (char) (nibble - 10)); } return digit; } private int _readObjectIntoObjectReference(char characters[], int index, Object objects[], String keypath, ParserDataStructureFactory factory) { index = _skipWhitespaceAndComments(characters, index); if (index == -1 || index >= characters.length) { objects[0] = null; } else if (characters[index] == '"') { StringBuffer buffer = new StringBuffer(64); index = _readQuotedStringIntoStringBuffer(characters, index, buffer); objects[0] = buffer.toString(); } else if (characters[index] == '<') { EMMutableData data = new EMMutableData(_lengthOfData(characters, index)); index = _readDataContentsIntoData(characters, index, data); objects[0] = data; } else if (characters[index] == '(') { Collection array = factory.createCollection(keypath); index = _readArrayContentsIntoArray(characters, index, array, keypath, factory); objects[0] = array; } else if (characters[index] == '{') { Map dictionary = factory.createMap(keypath); index = _readDictionaryContentsIntoDictionary(characters, index, dictionary, keypath, factory); objects[0] = dictionary; } else { StringBuffer buffer = new StringBuffer(64); index = _readUnquotedStringIntoStringBuffer(characters, index, buffer); objects[0] = buffer.toString(); } return index < characters.length ? index : -1; } private int _readUnquotedStringIntoStringBuffer(char characters[], int index, StringBuffer buffer) { int originalIndex = index; buffer.setLength(0); for (; index < characters.length && (characters[index] >= 'a' && characters[index] <= 'z' || characters[index] >= 'A' && characters[index] <= 'Z' || characters[index] >= '0' && characters[index] <= '9' || characters[index] == '_' || characters[index] == '$' || characters[index] == ':' || characters[index] == '.' || characters[index] == '/'); index++) { // DO NOTHING } if (originalIndex < index) { buffer.append(characters, originalIndex, index - originalIndex); } else { throw new IllegalArgumentException("Property list parsing failed while attempting to read unquoted string. No allowable characters were found. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } return index < characters.length ? index : -1; } private int _readQuotedStringIntoStringBuffer(char characters[], int index, StringBuffer buffer) { _saveIndexes(index, _lineNumber, _startOfLineCharIndex); int seqStart = ++index; while (index < characters.length && characters[index] != '"') { if (characters[index] == '\\') { if (seqStart < index) { buffer.append(characters, seqStart, index - seqStart); } if (++index >= characters.length) { throw new IllegalArgumentException("Property list parsing failed while attempting to read quoted string. Input exhausted before closing quote was found. Opening quote was at " + _savedIndexesAsString() + "."); } if (characters[index] == 'n') { buffer.append('\n'); index++; } else if (characters[index] == 'r') { buffer.append('\r'); index++; } else if (characters[index] == 't') { buffer.append('\t'); index++; } else if (characters[index] == 'f') { buffer.append('\f'); index++; } else if (characters[index] == 'b') { buffer.append('\b'); index++; } else if (characters[index] == 'a') { buffer.append('\007'); index++; } else if (characters[index] == 'v') { buffer.append('\013'); index++; } else if (characters[index] == 'u' || characters[index] == 'U') { if (index + 4 >= characters.length) { throw new IllegalArgumentException("Property list parsing failed while attempting to read quoted string. Input exhausted before escape sequence was completed. Opening quote was at " + _savedIndexesAsString() + "."); } index++; if (!_isHexDigit(characters[index]) || !_isHexDigit(characters[index + 1]) || !_isHexDigit(characters[index + 2]) || !_isHexDigit(characters[index + 3])) { throw new IllegalArgumentException("Property list parsing failed while attempting to read quoted string. Improperly formed \\U type escape sequence. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } byte nibble4 = _nibbleForHexDigit(characters[index]); byte nibble3 = _nibbleForHexDigit(characters[index + 1]); byte nibble2 = _nibbleForHexDigit(characters[index + 2]); byte nibble1 = _nibbleForHexDigit(characters[index + 3]); buffer.append((char) ((nibble4 << 12) + (nibble3 << 8) + (nibble2 << 4) + nibble1)); index += 4; } else if (characters[index] >= '0' && characters[index] <= '7') { int temp = 0; int numberOfDigits = 1; int digits[] = new int[3]; digits[0] = characters[index] - 48; for (index++; numberOfDigits < 3 && index < characters.length && characters[index] >= '0' && characters[index] <= '7'; index++) { digits[numberOfDigits++] = characters[index] - 48; } if (numberOfDigits == 3 && digits[0] > 3) { throw new IllegalArgumentException("Property list parsing failed while attempting to read quoted string. Octal escape sequence too large (bigger than octal 377). At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } for (int i = 0; i < numberOfDigits; i++) { temp *= 8; temp += digits[i]; } buffer.append(_nsToUnicode(temp)); } else { buffer.append(characters[index]); if (characters[index] == '\n') { _lineNumber++; _startOfLineCharIndex = index + 1; } index++; } seqStart = index; } else { if (characters[index] == '\n') { _lineNumber++; _startOfLineCharIndex = index + 1; } index++; } } if (seqStart < index) { buffer.append(characters, seqStart, index - seqStart); } if (index >= characters.length) { throw new IllegalArgumentException("Property list parsing failed while attempting to read quoted string. Input exhausted before closing quote was found. Opening quote was at " + _savedIndexesAsString() + "."); } return ++index < characters.length ? index : -1; } private int _lengthOfData(char characters[], int index) { int numberOfNibbles = 0; boolean isHex = false; for (index++; index < characters.length && ((isHex = _isHexDigit(characters[index])) || _isWhitespace(characters[index])); index++) { if (isHex) { numberOfNibbles++; } } if (index >= characters.length) { throw new IllegalArgumentException("Property list parsing failed while attempting to read data. Input exhausted before data was terminated with '>'. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } if (characters[index] != '>') { throw new IllegalArgumentException("Property list parsing failed while attempting to read data. Illegal character encountered in data: '" + characters[index] + "'. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } if (numberOfNibbles % 2 != 0) { throw new IllegalArgumentException("Property list parsing failed while attempting to read data. An odd number of half-bytes were specified. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } return numberOfNibbles / 2; } private int _readDataContentsIntoData(char characters[], int index, EMMutableData data) { index++; do { if (characters[index] == '>') { break; } index = _skipWhitespaceAndComments(characters, index); if (characters[index] == '>') { break; } byte nibble2 = _nibbleForHexDigit(characters[index]); index++; index = _skipWhitespaceAndComments(characters, index); byte nibble1 = _nibbleForHexDigit(characters[index]); index++; data.appendByte((byte) ((nibble2 << 4) + nibble1)); } while (true); return ++index < characters.length ? index : -1; } private int _readArrayContentsIntoArray(char characters[], int index, Collection array, String keypath, ParserDataStructureFactory factory) { Object objects[] = new Object[1]; index++; array.clear(); index = _skipWhitespaceAndComments(characters, index); do { if (index == -1 || characters[index] == ')') { break; } if (array.size() > 0) { if (characters[index] != ',') { throw new IllegalArgumentException("Property list parsing failed while attempting to read array. No comma found between array elements. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } index++; index = _skipWhitespaceAndComments(characters, index); if (index == -1) { throw new IllegalArgumentException("Property list parsing failed while attempting to read array. Input exhausted before end of array was found. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } } if (characters[index] != ')') { objects[0] = null; index = _readObjectIntoObjectReference(characters, index, objects, keypath, factory); if (objects[0] == null) { throw new IllegalArgumentException("Property list parsing failed while attempting to read array. Failed to read content object. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } index = _skipWhitespaceAndComments(characters, index); array.add(objects[0]); } } while (true); if (index == -1) { throw new IllegalArgumentException("Property list parsing failed while attempting to read array. Input exhausted before end of array was found. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } return ++index < characters.length ? index : -1; } private int _readDictionaryContentsIntoDictionary(char characters[], int index, Map dictionary, String keypath, ParserDataStructureFactory factory) { Object keys[] = new Object[1]; Object values[] = new Object[1]; index++; if (dictionary.size() != 0) { for (Iterator keyEnumerator = dictionary.keySet().iterator(); keyEnumerator.hasNext(); dictionary.remove(keyEnumerator.next())) { // DO NOTHING } } for (index = _skipWhitespaceAndComments(characters, index); index != -1 && characters[index] != '}';) { index = _readObjectIntoObjectReference(characters, index, keys, keypath, factory); if (keys[0] == null || !(keys[0] instanceof String)) { throw new IllegalArgumentException("Property list parsing failed while attempting to read dictionary. Failed to read key or key is not a String. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } index = _skipWhitespaceAndComments(characters, index); if (index == -1 || characters[index] != '=') { throw new IllegalArgumentException("Property list parsing failed while attempting to read dictionary. Read key " + keys[0] + " with no value. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } index++; index = _skipWhitespaceAndComments(characters, index); if (index == -1) { throw new IllegalArgumentException("Property list parsing failed while attempting to read dictionary. Read key " + keys[0] + " with no value. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } index = _readObjectIntoObjectReference(characters, index, values, keypath + "." + keys[0], factory); if (values[0] == null) { throw new IllegalArgumentException("Property list parsing failed while attempting to read dictionary. Failed to read value. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } index = _skipWhitespaceAndComments(characters, index); if (index == -1 || characters[index] != ';') { throw new IllegalArgumentException("Property list parsing failed while attempting to read dictionary. Read key and value with no terminating semicolon. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } index++; index = _skipWhitespaceAndComments(characters, index); dictionary.put(keys[0], values[0]); } if (index >= characters.length) { throw new IllegalArgumentException("Property list parsing failed while attempting to read dictionary. Exhausted input before end of dictionary was found. At line number: " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } return ++index < characters.length ? index : -1; } private int _skipWhitespaceAndComments(char characters[], int index) { for (int nextChar = _checkForWhitespaceOrComment(characters, index); nextChar != 1; nextChar = _checkForWhitespaceOrComment(characters, index)) { switch (nextChar) { case 2: index = _processWhitespace(characters, index); break; case 3: index = _processSingleLineComment(characters, index); break; case 4: index = _processMultiLineComment(characters, index); break; } } return index < characters.length ? index : -1; } private int _processWhitespace(char characters[], int index) { for (; index < characters.length && _isWhitespace(characters[index]); index++) { if (characters[index] == '\n') { _lineNumber++; _startOfLineCharIndex = index + 1; } } return index < characters.length ? index : -1; } private int _processSingleLineComment(char characters[], int index) { for (index += 2; index < characters.length && characters[index] != '\n'; index++) { // DO NOTHING } return index < characters.length ? index : -1; } private int _processMultiLineComment(char characters[], int index) { _saveIndexes(index, _lineNumber, _startOfLineCharIndex); for (index += 2; index + 1 < characters.length && (characters[index] != '*' || characters[index + 1] != '/'); index++) { if (characters[index] == '/' && characters[index + 1] == '*') { throw new IllegalArgumentException("Property list parsing does not support embedded multi line comments.The first /* was at " + _savedIndexesAsString() + ". A second /* was found at line " + _lineNumber + ", column: " + (index - _startOfLineCharIndex) + "."); } if (characters[index] == '\n') { _lineNumber++; _startOfLineCharIndex = index + 1; } } if (index + 1 < characters.length && characters[index] == '*' && characters[index + 1] == '/') { index += 2; } else { throw new IllegalArgumentException("Property list parsing failed while attempting to find closing */ to comment that began at " + _savedIndexesAsString() + "."); } return index < characters.length ? index : -1; } private int _checkForWhitespaceOrComment(char characters[], int index) { if (index == -1 || index >= characters.length) { return 1; } if (_isWhitespace(characters[index])) { return 2; } if (index + 1 < characters.length) { if (characters[index] == '/' && characters[index + 1] == '/') { return 3; } if (characters[index] == '/' && characters[index + 1] == '*') { return 4; } } return 1; } private static final byte _nibbleForHexDigit(char digit) { int nibble = 0; if (digit >= '0' && digit <= '9') { nibble = (byte) (digit - 48); } else if (digit >= 'a' && digit <= 'f') { nibble = (byte) ((digit - 97) + 10); } else if (digit >= 'A' && digit <= 'F') { nibble = (byte) ((digit - 65) + 10); } else { throw new IllegalArgumentException("Non-hex digit passed to _nibbleForHexDigit()"); } return (byte) nibble; } private static final boolean _isHexDigit(char c) { return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F'; } private static final boolean _isWhitespace(char c) { return c < 33 && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'); } private static char _nsToUnicode(int c) { return c >= 128 ? (char) NSToPrecompUnicodeTable[c - 128] : (char) c; } private _Utilities() { // DO NOTHING } } private WOLPropertyListSerialization() { throw new IllegalStateException("Can't instantiate an instance of class " + getClass().getName()); } public static String stringFromPropertyList(Object plist) throws PropertyListParserException { return _Utilities.stringFromPropertyList(plist); } public static Object propertyListFromString(String string) throws IOException, PropertyListParserException { return WOLPropertyListSerialization.propertyListFromString(string, new SimpleParserDataStructureFactory()); } public static Object propertyListFromString(String string, ParserDataStructureFactory factory) throws PropertyListParserException { return _Utilities.propertyListFromString(string, factory); } public static Object propertyListWithPathURL(URL url, ParserDataStructureFactory factory) throws IOException, PropertyListParserException { String string = WOLPropertyListSerialization.stringFromURL(url); return propertyListFromString(string, factory); } public static Object propertyListWithContentsOfInputStream(InputStream inputStream, ParserDataStructureFactory factory) throws IOException, PropertyListParserException { String string = WOLPropertyListSerialization.stringFromInputStream(inputStream); return propertyListFromString(string, factory); } public static Object propertyListWithContentsOfFile(String path, ParserDataStructureFactory factory) throws IOException, PropertyListParserException { return _Utilities.propertyListWithContentsOfFile(path, factory); } public static String stringFromFile(File f) throws IOException { return new String(bytesFromFile(f)); } public static String stringFromFile(File f, String encoding) throws IOException { if (encoding == null) { return new String(bytesFromFile(f)); } return new String(bytesFromFile(f), encoding); } public static byte[] bytesFromFile(File f) throws IOException { return bytesFromFile(f, (int) f.length()); } public static byte[] bytesFromFile(File f, int n) throws IOException { FileInputStream fis = new FileInputStream(f); byte[] data = new byte[n]; int bytesRead = 0; while (bytesRead < n) { bytesRead += fis.read(data, bytesRead, n - bytesRead); } fis.close(); return data; } public static byte[] bytesFromInputStream(InputStream in) throws IOException { if (in == null) throw new IOException("null input stream"); ByteArrayOutputStream bout = new ByteArrayOutputStream(); int read = -1; byte[] buf = new byte[1024 * 50]; while ((read = in.read(buf)) != -1) { bout.write(buf, 0, read); } return bout.toByteArray(); } public static String stringFromInputStream(InputStream in) throws IOException { return new String(bytesFromInputStream(in)); } public static String stringFromInputStream(InputStream in, String encoding) throws IOException { return new String(bytesFromInputStream(in), encoding); } public static String stringFromURL(URL url) throws IOException { InputStream is = url.openStream(); try { return stringFromInputStream(is); } finally { is.close(); } } public static String stringFromURL(URL url, String encoding) throws IOException { InputStream is = url.openStream(); try { return stringFromInputStream(is, encoding); } finally { is.close(); } } public static class EMMutableData { private ByteArrayOutputStream _stream; public EMMutableData(int size) { _stream = new ByteArrayOutputStream(size); } public EMMutableData(ByteArrayOutputStream stream) { _stream = stream; } public byte[] bytes() { return _stream.toByteArray(); } public EMMutableData clone() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { baos.write(bytes()); } catch (IOException e) { throw new RuntimeException(e); } return new EMMutableData(baos); } public void appendByte(byte b) { _stream.write(b); } public boolean isEqualToData(EMMutableData data) { boolean equal; if (data == this) { equal = true; } else { byte[] b1 = bytes(); byte[] b2 = data.bytes(); if (b1.length != b2.length) { equal = false; } else { equal = true; for (int i = 0; equal && i < b1.length; i++) { equal = b1[i] == b2[i]; } } } return equal; } } /** * Reads a property list file. Returns a property list object, that is * normally a java.util.List or a java.util.Map, but can also be a String or * a Number. * * @throws PropertyListParserException */ public static Object propertyListFromFile(File f) throws IOException, PropertyListParserException { return WOLPropertyListSerialization.propertyListWithPathURL(f.toURL(), new SimpleParserDataStructureFactory()); } /** * Reads a property list file. Returns a property list object, that is * normally a java.util.List or a java.util.Map, but can also be a String or * a Number. * * @throws PropertyListParserException */ public static Object propertyListFromFile(File f, ParserDataStructureFactory factory) throws IOException, PropertyListParserException { return WOLPropertyListSerialization.propertyListWithPathURL(f.toURL(), factory); } /** * Reads a property list file. Returns a property list object, that is * normally a java.util.List or a java.util.Map, but can also be a String or * a Number. * * @throws IOException * @throws PropertyListParserException */ public static Object propertyListFromURL(URL u, ParserDataStructureFactory factory) throws IOException, PropertyListParserException { return WOLPropertyListSerialization.propertyListWithPathURL(u, factory); } /** * Reads a property list data from InputStream. Returns a property list o * bject, that is normally a java.util.List or a java.util.Map, but can also * be a String or a Number. * * @throws IOException * @throws PropertyListParserException */ public static Object propertyListFromStream(InputStream in) throws IOException, PropertyListParserException { return WOLPropertyListSerialization.propertyListWithContentsOfInputStream(in, new SimpleParserDataStructureFactory()); } /** * Reads a property list data from InputStream. Returns a property list o * bject, that is normally a java.util.List or a java.util.Map, but can also * be a String or a Number. * * @throws IOException * @throws PropertyListParserException */ public static Object propertyListFromStream(InputStream in, ParserDataStructureFactory factory) throws IOException, PropertyListParserException { return WOLPropertyListSerialization.propertyListWithContentsOfInputStream(in, factory); } /** * Saves property list to file. * * @throws PropertyListParserException * @throws IOException */ public static void propertyListToFile(@SuppressWarnings("unused") String header, File f, Object plist) throws PropertyListParserException, IOException { BufferedWriter out = null; try { String str = WOLPropertyListSerialization.stringFromPropertyList(plist); if (str != null) { try { Object existingPlistContent = propertyListFromFile(f); Object newPlistContent = WOLPropertyListSerialization.propertyListFromString(str, new SimpleParserDataStructureFactory()); if (existingPlistContent.equals(newPlistContent)) { return; } } catch (Exception e) { // in this case, just proceed to write it out } out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), Charset.forName("UTF-8"))); /* * if (header != null && header.length() > 0) { out.append("// " + * header); out.append("\n"); } */ out.write(str); if (str.length() > 0 && str.charAt(str.length() - 1) != '\n') { out.write('\n'); } } // writeObject("", out, plist); } finally { if (out != null) { out.close(); } } } /** * Saves property list to file. * * @throws PropertyListParserException * @throws IOException */ public static void propertyListToStream(OutputStream os, Object plist) throws PropertyListParserException, IOException { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(os/* * , * Charset.forName("UTF-8") */)); try { String str = WOLPropertyListSerialization.stringFromPropertyList(plist); if (str != null) { out.write(str); } } finally { out.close(); } }}