From 709984d829f7d84097e899b55fb573d777e427dc Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 5 Apr 2016 18:29:00 +0000 Subject: Upgrade dd_plist to version 1.17 Pair programmed with @matvore to reapply internal patches. -- MOS_MIGRATED_REVID=119071196 --- third_party/java/dd_plist/README | 6 +- .../java/dd_plist/java/com/dd/plist/Base64.java | 70 +++-- .../com/dd/plist/BinaryPropertyListParser.java | 343 ++++++++++----------- .../com/dd/plist/BinaryPropertyListWriter.java | 12 +- .../java/dd_plist/java/com/dd/plist/NSArray.java | 9 +- .../java/dd_plist/java/com/dd/plist/NSDate.java | 15 +- .../dd_plist/java/com/dd/plist/NSDictionary.java | 38 +-- .../java/dd_plist/java/com/dd/plist/NSNumber.java | 25 +- .../java/dd_plist/java/com/dd/plist/NSObject.java | 4 +- .../java/dd_plist/java/com/dd/plist/NSSet.java | 3 +- .../java/dd_plist/java/com/dd/plist/NSString.java | 20 +- .../java/com/dd/plist/PropertyListParser.java | 93 +++++- .../java/com/dd/plist/XMLPropertyListParser.java | 52 +++- 13 files changed, 381 insertions(+), 309 deletions(-) (limited to 'third_party/java/dd_plist') diff --git a/third_party/java/dd_plist/README b/third_party/java/dd_plist/README index cd24c554a0..a2df2f881b 100644 --- a/third_party/java/dd_plist/README +++ b/third_party/java/dd_plist/README @@ -1,5 +1,5 @@ -URL: http://plist.googlecode.com/svn-history/r111/trunk/ -Version: r111 +URL: https://github.com/3breadt/dd-plist/tree/dd-plist-1.17 +Version: c48d54f5153ff38810e602d998bb9e029738655c License: MIT Style License File: LICENSE @@ -24,8 +24,6 @@ library can be of great help when it comes to porting iOS apps to Android. Local Modifications: - LICENSE file has been created for compliance purposes. Not included in original distribution. -- Made PropertyListParser.readAll react properly to InputStreams that sometimes - read fewer bytes than are available. - Rewrote some functions in ASCIIPropertyListParser.java to support characters outside of the 7-bit ASCII range. - Support surrogate pairs from \u escaped chars in strings in diff --git a/third_party/java/dd_plist/java/com/dd/plist/Base64.java b/third_party/java/dd_plist/java/com/dd/plist/Base64.java index 8a20f43891..e6a7ae3557 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/Base64.java +++ b/third_party/java/dd_plist/java/com/dd/plist/Base64.java @@ -26,37 +26,38 @@ package com.dd.plist; /** *

Encodes and decodes to and from Base64 notation.

*

Homepage: http://iharder.net/base64.

- *

+ * *

Example:

- *

+ * * String encoded = Base64.encode( myByteArray ); - *
+ * * byte[] myByteArray = Base64.decode( encoded ); - *

+ * *

The options parameter, which appears in a few places, is used to pass * several pieces of information to the encoder. In the "higher level" methods such as * encodeBytes( bytes, options ) the options parameter can be used to indicate such * things as first gzipping the bytes before encoding them, not inserting linefeeds, * and encoding using the URL-safe and Ordered dialects.

- *

+ * *

Note, according to RFC3548, * Section 2.1, implementations should not add line feeds unless explicitly told * to do so. I've got Base64 set to this behavior now, although earlier versions * broke lines by default.

- *

+ * *

The constants defined in Base64 can be OR-ed together to combine options, so you * might make a call like this:

- *

+ * * String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES ); *

to compress the data before encoding it and then making the output have newline characters.

*

Also...

* String encoded = Base64.encodeBytes( crazyString.getBytes() ); - *

- *

- *

+ * + * + * *

* Change Log: *

+ * * - *

+ * *

* I am placing this code in the Public Domain. Do with it as you will. * This software comes with no guarantees or warranties but with @@ -640,13 +641,13 @@ public class Base64 { /** * Serializes an object and returns the Base64-encoded * version of that serialized object. - *

+ * *

As of v 2.3, if the object * cannot be serialized or there is another error, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned a null value, but * in retrospect that's a pretty poor way to handle it.

- *

+ * * The object is not GZip-compressed before being encoded. * * @param serializableObject The object to encode @@ -664,22 +665,22 @@ public class Base64 { /** * Serializes an object and returns the Base64-encoded * version of that serialized object. - *

+ * *

As of v 2.3, if the object * cannot be serialized or there is another error, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned a null value, but * in retrospect that's a pretty poor way to handle it.

- *

+ * * The object is not GZip-compressed before being encoded. - *

+ * * Example options:

      *   GZIP: gzip-compresses object before encoding it.
      *   DO_BREAK_LINES: break lines at 76 characters
      * 
- *

+ * * Example: encodeObject( myObj, Base64.GZIP ) or - *

+ * * Example: encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES ) * * @param serializableObject The object to encode @@ -790,8 +791,8 @@ public class Base64 { * Example: encodeBytes( myData, Base64.GZIP ) or *

* Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES ) - *

- *

+ * + * *

As of v 2.3, if there is an error with the GZIP stream, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned a null value, but @@ -814,7 +815,7 @@ public class Base64 { /** * Encodes a byte array into Base64 notation. * Does not GZip-compress data. - *

+ * *

As of v 2.3, if there is an error, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned a null value, but @@ -855,8 +856,8 @@ public class Base64 { * Example: encodeBytes( myData, Base64.GZIP ) or *

* Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES ) - *

- *

+ * + * *

As of v 2.3, if there is an error with the GZIP stream, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned a null value, but @@ -1160,6 +1161,7 @@ public class Base64 { * @param source The Base64 encoded data * @return decoded data * @since 2.3.1 + * @throws java.io.IOException If bogus characters are contained in the input */ public static byte[] decode(byte[] source) throws java.io.IOException { @@ -1444,7 +1446,7 @@ public class Base64 { /** * Convenience method for encoding data to a file. - *

+ * *

As of v 2.3, if there is a error, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned false, but @@ -1484,7 +1486,7 @@ public class Base64 { /** * Convenience method for decoding data to a file. - *

+ * *

As of v 2.3, if there is a error, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned false, but @@ -1520,7 +1522,7 @@ public class Base64 { /** * Convenience method for reading a base64-encoded * file and decoding it. - *

+ * *

As of v 2.3, if there is a error, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned false, but @@ -1581,7 +1583,7 @@ public class Base64 { /** * Convenience method for reading a binary file * and base64-encoding it. - *

+ * *

As of v 2.3, if there is a error, * the method will throw an java.io.IOException. This is new to v2.3! * In earlier versions, it just returned false, but @@ -1729,13 +1731,13 @@ public class Base64 { /** * Constructs a {@link com.dd.plist.Base64.B64InputStream} in * either ENCODE or DECODE mode. - *

+ * * Valid options:

          *   ENCODE or DECODE: Encode or Decode as data is read.
          *   DO_BREAK_LINES: break lines at 76 characters
-         *     (only meaningful when encoding)
+         *     (only meaningful when encoding)
          * 
- *

+ * * Example: new Base64.B64InputStream( in, Base64.DECODE ) * * @param in the java.io.InputStream from which to read data. @@ -1940,13 +1942,13 @@ public class Base64 { /** * Constructs a {@link com.dd.plist.Base64.B64OutputStream} in * either ENCODE or DECODE mode. - *

+ * * Valid options:

          *   ENCODE or DECODE: Encode or Decode as data is read.
          *   DO_BREAK_LINES: don't break lines at 76 characters
-         *     (only meaningful when encoding)
+         *     (only meaningful when encoding)
          * 
- *

+ * * Example: new Base64.B64OutputStream( out, Base64.ENCODE ) * * @param out the java.io.B64OutputStream to which data will be written. diff --git a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java b/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java index ee2ca7ada6..9b201016b6 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java +++ b/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java @@ -23,51 +23,44 @@ package com.dd.plist; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.math.BigInteger; /** * Parses property lists that are in Apple's binary format. * Use this class when you are sure about the format of the property list. * Otherwise use the PropertyListParser class. - *

+ * * Parsing is done by calling the static parse methods. * * @author Daniel Dreibrodt */ public class BinaryPropertyListParser { - private int majorVersion, minorVersion; - - /** - * property list in bytes * - */ - private byte[] bytes; - /** - * Length of an offset definition in bytes * - */ - private int offsetSize; /** - * Length of an object reference in bytes * + * Major version of the property list format */ - private int objectRefSize; + @SuppressWarnings("FieldCanBeLocal") //Useful when the features of different format versions are implemented + private int majorVersion; + /** - * Number of objects stored in this property list * + * Minor version of the property list format */ - private int numObjects; + @SuppressWarnings("FieldCanBeLocal") //Useful when the features of different format versions are implemented + private int minorVersion; + /** - * Reference to the top object of the property list * + * property list in bytes */ - private int topObject; + private byte[] bytes; + /** - * Offset of the offset table from the beginning of the file * + * Length of an object reference in bytes */ - private int offsetTableOffset; + private int objectRefSize; + /** - * The table holding the information at which offset each object is found * + * The table holding the information at which offset each object is found */ private int[] offsetTable; @@ -85,10 +78,11 @@ public class BinaryPropertyListParser { * Parses a binary property list from a byte array. * * @param data The binary property list's data. - * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray. - * @throws Exception When an error occurs during parsing. + * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + * @throws PropertyListFormatException When the property list's format could not be parsed. + * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded. */ - public static NSObject parse(byte[] data) throws IOException, PropertyListFormatException { + public static NSObject parse(byte[] data) throws PropertyListFormatException, UnsupportedEncodingException { BinaryPropertyListParser parser = new BinaryPropertyListParser(); return parser.doParse(data); } @@ -97,10 +91,11 @@ public class BinaryPropertyListParser { * Parses a binary property list from a byte array. * * @param data The binary property list's data. - * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray. - * @throws Exception When an error occurs during parsing. + * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + * @throws PropertyListFormatException When the property list's format could not be parsed. + * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded. */ - private NSObject doParse(byte[] data) throws IOException, PropertyListFormatException { + private NSObject doParse(byte[] data) throws PropertyListFormatException, UnsupportedEncodingException { bytes = data; String magic = new String(copyOfRange(bytes, 0, 8)); if (!magic.startsWith("bplist")) { @@ -119,6 +114,7 @@ public class BinaryPropertyListParser { if (majorVersion > 0) { throw new IllegalArgumentException("Unsupported binary property list format: v" + majorVersion + "." + minorVersion + ". " + "Version 1.0 and later are not yet supported."); + //Version 1.0+ is not even supported by OS X's own parser } /* @@ -126,16 +122,12 @@ public class BinaryPropertyListParser { */ byte[] trailer = copyOfRange(bytes, bytes.length - 32, bytes.length); //6 null bytes (index 0 to 5) - offsetSize = (int) parseUnsignedInt(trailer, 6, 7); - //System.out.println("offsetSize: "+offsetSize); + + int offsetSize = (int) parseUnsignedInt(trailer, 6, 7); objectRefSize = (int) parseUnsignedInt(trailer, 7, 8); - //System.out.println("objectRefSize: "+objectRefSize); - numObjects = (int) parseUnsignedInt(trailer, 8, 16); - //System.out.println("numObjects: "+numObjects); - topObject = (int) parseUnsignedInt(trailer, 16, 24); - //System.out.println("topObject: "+topObject); - offsetTableOffset = (int) parseUnsignedInt(trailer, 24, 32); - //System.out.println("offsetTableOffset: "+offsetTableOffset); + int numObjects = (int) parseUnsignedInt(trailer, 8, 16); + int topObject = (int) parseUnsignedInt(trailer, 16, 24); + int offsetTableOffset = (int) parseUnsignedInt(trailer, 24, 32); /* * Handle offset table @@ -143,11 +135,7 @@ public class BinaryPropertyListParser { offsetTable = new int[numObjects]; for (int i = 0; i < numObjects; i++) { - byte[] offsetBytes = copyOfRange(bytes, offsetTableOffset + i * offsetSize, offsetTableOffset + (i + 1) * offsetSize); - offsetTable[i] = (int) parseUnsignedInt(offsetBytes); - /*System.out.print("Offset for Object #"+i+" is "+offsetTable[i]+" ["); - for(byte b:offsetBytes) System.out.print(Integer.toHexString(b)+" "); - System.out.println("]");*/ + offsetTable[i] = (int) parseUnsignedInt(bytes, offsetTableOffset + i * offsetSize, offsetTableOffset + (i + 1) * offsetSize); } return parseObject(topObject); @@ -157,13 +145,12 @@ public class BinaryPropertyListParser { * Parses a binary property list from an input stream. * * @param is The input stream that points to the property list's data. - * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray. - * @throws Exception When an error occurs during parsing. + * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + * @throws PropertyListFormatException When the property list's format could not be parsed. + * @throws java.io.IOException When a NSString object could not be decoded or an InputStream IO error occurs. */ public static NSObject parse(InputStream is) throws IOException, PropertyListFormatException { - //Read all bytes into a list byte[] buf = PropertyListParser.readAll(is); - is.close(); return parse(buf); } @@ -171,27 +158,26 @@ public class BinaryPropertyListParser { * Parses a binary property list file. * * @param f The binary property list file - * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray. - * @throws Exception When an error occurs during parsing. + * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + * @throws PropertyListFormatException When the property list's format could not be parsed. + * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded or a file IO error occurs. */ public static NSObject parse(File f) throws IOException, PropertyListFormatException { - if (f.length() > Runtime.getRuntime().freeMemory()) { - throw new OutOfMemoryError("To little heap space available! Wanted to read " + f.length() + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available."); - } return parse(new FileInputStream(f)); } /** * Parses an object inside the currently parsed binary property list. * For the format specification check - * + * * Apple's binary property list parser implementation. * * @param obj The object ID. * @return The parsed object. - * @throws java.lang.Exception When an error occurs during parsing. + * @throws PropertyListFormatException When the property list's format could not be parsed. + * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded. */ - private NSObject parseObject(int obj) throws IOException, PropertyListFormatException { + private NSObject parseObject(int obj) throws PropertyListFormatException, UnsupportedEncodingException { int offset = offsetTable[obj]; byte type = bytes[offset]; int objType = (type & 0xF0) >> 4; //First 4 bits @@ -214,182 +200,140 @@ public class BinaryPropertyListParser { } case 0xC: { //URL with no base URL (v1.0 and later) - //TODO - break; + //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17) + throw new UnsupportedOperationException("The given binary property list contains a URL object. Parsing of this object type is not yet implemented."); } case 0xD: { //URL with base URL (v1.0 and later) - //TODO - break; + //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17) + throw new UnsupportedOperationException("The given binary property list contains a URL object. Parsing of this object type is not yet implemented."); } case 0xE: { //16-byte UUID (v1.0 and later) - //TODO - break; + //TODO Implement binary UUID parsing (not yet even implemented in Core Foundation as of revision 855.17) + throw new UnsupportedOperationException("The given binary property list contains a UUID object. Parsing of this object type is not yet implemented."); } - case 0xF: { - //filler byte - return null; + default: { + throw new PropertyListFormatException("The given binary property list contains an object of unknown type (" + objType + ")"); } } - break; } case 0x1: { //integer int length = (int) Math.pow(2, objInfo); - if (length < Runtime.getRuntime().freeMemory()) { - return new NSNumber(copyOfRange(bytes, offset + 1, offset + 1 + length), NSNumber.INTEGER); - } else { - throw new OutOfMemoryError("To little heap space available! Wanted to read " + length + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available."); - } + return new NSNumber(bytes, offset + 1, offset + 1 + length, NSNumber.INTEGER); } case 0x2: { //real int length = (int) Math.pow(2, objInfo); - if (length < Runtime.getRuntime().freeMemory()) { - return new NSNumber(copyOfRange(bytes, offset + 1, offset + 1 + length), NSNumber.REAL); - } else { - throw new OutOfMemoryError("To little heap space available! Wanted to read " + length + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available."); - } + return new NSNumber(bytes, offset + 1, offset + 1 + length, NSNumber.REAL); } case 0x3: { //Date if (objInfo != 0x3) { throw new PropertyListFormatException("The given binary property list contains a date object of an unknown type ("+objInfo+")"); } - return new NSDate(copyOfRange(bytes, offset + 1, offset + 9)); + return new NSDate(bytes, offset + 1, offset + 9); } case 0x4: { //Data - int[] lenAndoffset = readLengthAndOffset(objInfo, offset); - int length = lenAndoffset[0]; - int dataoffset = lenAndoffset[1]; - - if (length < Runtime.getRuntime().freeMemory()) { - return new NSData(copyOfRange(bytes, offset + dataoffset, offset + dataoffset + length)); - } else { - throw new OutOfMemoryError("To little heap space available! Wanted to read " + length + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available."); - } + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int length = lengthAndOffset[0]; + int dataOffset = lengthAndOffset[1]; + return new NSData(copyOfRange(bytes, offset + dataOffset, offset + dataOffset + length)); } case 0x5: { - //ASCII String - int[] lenAndoffset = readLengthAndOffset(objInfo, offset); - int length = lenAndoffset[0]; - int stroffset = lenAndoffset[1]; - - if (length < Runtime.getRuntime().freeMemory()) { - return new NSString(copyOfRange(bytes, offset + stroffset, offset + stroffset + length), "ASCII"); - } else { - throw new OutOfMemoryError("To little heap space available! Wanted to read " + length + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available."); - } + //ASCII string + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int length = lengthAndOffset[0]; //Each character is 1 byte + int strOffset = lengthAndOffset[1]; + return new NSString(bytes, offset + strOffset, offset + strOffset + length, "ASCII"); } case 0x6: { - //UTF-16-BE String - int[] lenAndoffset = readLengthAndOffset(objInfo, offset); - int length = lenAndoffset[0]; - int stroffset = lenAndoffset[1]; - - //length is String length -> to get byte length multiply by 2, as 1 character takes 2 bytes in UTF-16 - length *= 2; - if (length < Runtime.getRuntime().freeMemory()) { - return new NSString(copyOfRange(bytes, offset + stroffset, offset + stroffset + length), "UTF-16BE"); - } else { - throw new OutOfMemoryError("To little heap space available! Wanted to read " + length + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available."); - } + //UTF-16-BE string + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int characters = lengthAndOffset[0]; + int strOffset = lengthAndOffset[1]; + //UTF-16 characters can have variable length, but the Core Foundation reference implementation + //assumes 2 byte characters, thus only covering the Basic Multilingual Plane + int length = characters * 2; + return new NSString(bytes, offset + strOffset, offset + strOffset + length, "UTF-16BE"); + } + case 0x7: { + //UTF-8 string (v1.0 and later) + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int strOffset = lengthAndOffset[1]; + int characters = lengthAndOffset[0]; + //UTF-8 characters can have variable length, so we need to calculate the byte length dynamically + //by reading the UTF-8 characters one by one + int length = calculateUtf8StringLength(bytes, offset + strOffset, characters); + return new NSString(bytes, offset + strOffset, offset + strOffset + length, "UTF-8"); } case 0x8: { - //UID + //UID (v1.0 and later) int length = objInfo + 1; - if (length < Runtime.getRuntime().freeMemory()) { - return new UID(String.valueOf(obj), copyOfRange(bytes, offset + 1, offset + 1 + length)); - } else { - throw new OutOfMemoryError("To little heap space available! Wanted to read " + length + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available."); - } + return new UID(String.valueOf(obj), copyOfRange(bytes, offset + 1, offset + 1 + length)); } case 0xA: { //Array - int[] lenAndoffset = readLengthAndOffset(objInfo, offset); - int length = lenAndoffset[0]; - int arrayoffset = lenAndoffset[1]; + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int length = lengthAndOffset[0]; + int arrayOffset = lengthAndOffset[1]; - if (length * objectRefSize > Runtime.getRuntime().freeMemory()) { - throw new OutOfMemoryError("To little heap space available!"); - } NSArray array = new NSArray(length); for (int i = 0; i < length; i++) { - int objRef = (int) parseUnsignedInt(copyOfRange(bytes, - offset + arrayoffset + i * objectRefSize, - offset + arrayoffset + (i + 1) * objectRefSize)); + int objRef = (int) parseUnsignedInt(bytes, offset + arrayOffset + i * objectRefSize, offset + arrayOffset + (i + 1) * objectRefSize); array.setValue(i, parseObject(objRef)); } return array; - } case 0xB: { - //Ordered set - int[] lenAndoffset = readLengthAndOffset(objInfo, offset); - int length = lenAndoffset[0]; - int contentOffset = lenAndoffset[1]; + //Ordered set (v1.0 and later) + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int length = lengthAndOffset[0]; + int contentOffset = lengthAndOffset[1]; - if (length * objectRefSize > Runtime.getRuntime().freeMemory()) { - throw new OutOfMemoryError("To little heap space available!"); - } NSSet set = new NSSet(true); for (int i = 0; i < length; i++) { - int objRef = (int) parseUnsignedInt(copyOfRange(bytes, - offset + contentOffset + i * objectRefSize, - offset + contentOffset + (i + 1) * objectRefSize)); + int objRef = (int) parseUnsignedInt(bytes, offset + contentOffset + i * objectRefSize, offset + contentOffset + (i + 1) * objectRefSize); set.addObject(parseObject(objRef)); } return set; } case 0xC: { - //Set - int[] lenAndoffset = readLengthAndOffset(objInfo, offset); - int length = lenAndoffset[0]; - int contentOffset = lenAndoffset[1]; + //Set (v1.0 and later) + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int length = lengthAndOffset[0]; + int contentOffset = lengthAndOffset[1]; - if (length * objectRefSize > Runtime.getRuntime().freeMemory()) { - throw new OutOfMemoryError("To little heap space available!"); - } NSSet set = new NSSet(); for (int i = 0; i < length; i++) { - int objRef = (int) parseUnsignedInt(copyOfRange(bytes, - offset + contentOffset + i * objectRefSize, - offset + contentOffset + (i + 1) * objectRefSize)); + int objRef = (int) parseUnsignedInt(bytes, offset + contentOffset + i * objectRefSize, offset + contentOffset + (i + 1) * objectRefSize); set.addObject(parseObject(objRef)); } return set; } case 0xD: { //Dictionary - int[] lenAndoffset = readLengthAndOffset(objInfo, offset); - int length = lenAndoffset[0]; - int contentOffset = lenAndoffset[1]; + int[] lengthAndOffset = readLengthAndOffset(objInfo, offset); + int length = lengthAndOffset[0]; + int contentOffset = lengthAndOffset[1]; - if (length * 2 * objectRefSize > Runtime.getRuntime().freeMemory()) { - throw new OutOfMemoryError("To little heap space available!"); - } - //System.out.println("Parsing dictionary #"+obj); NSDictionary dict = new NSDictionary(); for (int i = 0; i < length; i++) { - int keyRef = (int) parseUnsignedInt(copyOfRange(bytes, - offset + contentOffset + i * objectRefSize, - offset + contentOffset + (i + 1) * objectRefSize)); - int valRef = (int) parseUnsignedInt(copyOfRange(bytes, - offset + contentOffset + (length * objectRefSize) + i * objectRefSize, - offset + contentOffset + (length * objectRefSize) + (i + 1) * objectRefSize)); + int keyRef = (int) parseUnsignedInt(bytes, offset + contentOffset + i * objectRefSize, offset + contentOffset + (i + 1) * objectRefSize); + int valRef = (int) parseUnsignedInt(bytes, offset + contentOffset + (length * objectRefSize) + i * objectRefSize, offset + contentOffset + (length * objectRefSize) + (i + 1) * objectRefSize); NSObject key = parseObject(keyRef); NSObject val = parseObject(valRef); + assert key != null; //Encountering a null object at this point would either be a fundamental error in the parser or an error in the property list dict.put(key.toString(), val); } return dict; } default: { - System.err.println("WARNING: The given binary property list contains an object of unknown type (" + objType + ")"); + throw new PropertyListFormatException("The given binary property list contains an object of unknown type (" + objType + ")"); } } - return null; } /** @@ -400,8 +344,8 @@ public class BinaryPropertyListParser { * @return An array with the length two. First entry is the length, second entry the offset at which the content starts. */ private int[] readLengthAndOffset(int objInfo, int offset) { - int length = objInfo; - int stroffset = 1; + int lengthValue = objInfo; + int offsetValue = 1; if (objInfo == 0xF) { int int_type = bytes[offset + 1]; int intType = (int_type & 0xF0) >> 4; @@ -410,14 +354,57 @@ public class BinaryPropertyListParser { } int intInfo = int_type & 0x0F; int intLength = (int) Math.pow(2, intInfo); - stroffset = 2 + intLength; + offsetValue = 2 + intLength; if (intLength < 3) { - length = (int) parseUnsignedInt(copyOfRange(bytes, offset + 2, offset + 2 + intLength)); + lengthValue = (int) parseUnsignedInt(bytes, offset + 2, offset + 2 + intLength); } else { - length = new BigInteger(copyOfRange(bytes, offset + 2, offset + 2 + intLength)).intValue(); + lengthValue = new BigInteger(copyOfRange(bytes, offset + 2, offset + 2 + intLength)).intValue(); + } + } + return new int[]{lengthValue, offsetValue}; + } + + private int calculateUtf8StringLength(byte[] bytes, int offset, int numCharacters) { + int length = 0; + for(int i = 0; i < numCharacters; i++) { + int tempOffset = offset + length; + if(bytes.length <= tempOffset) { + //WARNING: Invalid UTF-8 string, fall back to length = number of characters + return numCharacters; + } + if(bytes[tempOffset] < 0x80) { + length++; + } + if(bytes[tempOffset] < 0xC2) { + //Invalid value (marks continuation byte), fall back to length = number of characters + return numCharacters; + } + else if(bytes[tempOffset] < 0xE0) { + if((bytes[tempOffset + 1] & 0xC0) != 0x80) { + //Invalid continuation byte, fall back to length = number of characters + return numCharacters; + } + length += 2; + } + else if(bytes[tempOffset] < 0xF0) { + if((bytes[tempOffset + 1] & 0xC0) != 0x80 + || (bytes[tempOffset + 2] & 0xC0) != 0x80) { + //Invalid continuation byte, fall back to length = number of characters + return numCharacters; + } + length += 3; + } + else if(bytes[tempOffset] < 0xF5) { + if((bytes[tempOffset + 1] & 0xC0) != 0x80 + || (bytes[tempOffset + 2] & 0xC0) != 0x80 + || (bytes[tempOffset + 3] & 0xC0) != 0x80) { + //Invalid continuation byte, fall back to length = number of characters + return numCharacters; + } + length += 4; } } - return new int[]{length, stroffset}; + return length; } /** @@ -426,14 +413,9 @@ public class BinaryPropertyListParser { * @param bytes The byte array containing the unsigned integer. * @return The unsigned integer represented by the given bytes. */ + @SuppressWarnings("unused") public static long parseUnsignedInt(byte[] bytes) { - long l = 0; - for (byte b : bytes) { - l <<= 8; - l |= b & 0xFF; - } - l &= 0xFFFFFFFFL; - return l; + return parseUnsignedInt(bytes, 0, bytes.length); } /** @@ -460,13 +442,9 @@ public class BinaryPropertyListParser { * @param bytes The bytes representing the long integer. * @return The long integer represented by the given bytes. */ + @SuppressWarnings("unused") public static long parseLong(byte[] bytes) { - long l = 0; - for (byte b : bytes) { - l <<= 8; - l |= b & 0xFF; - } - return l; + return parseLong(bytes, 0, bytes.length); } /** @@ -492,14 +470,9 @@ public class BinaryPropertyListParser { * @param bytes The bytes representing the double. * @return The double represented by the given bytes. */ + @SuppressWarnings("unused") public static double parseDouble(byte[] bytes) { - if (bytes.length == 8) { - return Double.longBitsToDouble(parseLong(bytes)); - } else if (bytes.length == 4) { - return Float.intBitsToFloat((int) parseLong(bytes)); - } else { - throw new IllegalArgumentException("bad byte array length " + bytes.length); - } + return parseDouble(bytes, 0, bytes.length); } /** diff --git a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java b/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java index 1ab0b5de8b..c7b5315fb7 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java +++ b/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java @@ -91,7 +91,8 @@ public class BinaryPropertyListWriter { * * @param file the file to write to * @param root the source of the data to write to the file - * @throws IOException + * @throws IOException When an IO error occurs while writing to the file or the object structure contains + * data that cannot be saved. */ public static void write(File file, NSObject root) throws IOException { OutputStream out = new FileOutputStream(file); @@ -104,7 +105,8 @@ public class BinaryPropertyListWriter { * * @param out the stream to write to * @param root the source of the data to write to the stream - * @throws IOException + * @throws IOException When an IO error occurs while writing to the stream or the object structure contains + * data that cannot be saved. */ public static void write(OutputStream out, NSObject root) throws IOException { int minVersion = getMinimumRequiredVersion(root); @@ -123,7 +125,8 @@ public class BinaryPropertyListWriter { * * @param root The root object of the property list * @return The byte array containing the serialized property list - * @throws IOException + * @throws IOException When an IO error occurs while writing to the stream or the object structure contains + * data that cannot be saved. */ public static byte[] writeToArray(NSObject root) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); @@ -147,7 +150,8 @@ public class BinaryPropertyListWriter { * Creates a new binary property list writer * * @param outStr The output stream into which the binary property list will be written - * @throws IOException If an error occured while writing to the stream + * @throws IOException When an IO error occurs while writing to the stream or the object structure contains + * data that cannot be saved. */ BinaryPropertyListWriter(OutputStream outStr) throws IOException { out = new BufferedOutputStream(outStr); diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSArray.java b/third_party/java/dd_plist/java/com/dd/plist/NSArray.java index b8324c1bff..a0b2a4db29 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/NSArray.java +++ b/third_party/java/dd_plist/java/com/dd/plist/NSArray.java @@ -88,8 +88,6 @@ public class NSArray extends NSObject { * @param value The object. */ public void setValue(int key, Object value) { - if(value == null) - throw new NullPointerException("Cannot add null values to an NSArray!"); array[key] = NSObject.wrap(value); } @@ -123,6 +121,11 @@ public class NSArray extends NSObject { public boolean containsObject(Object obj) { NSObject nso = NSObject.wrap(obj); for (NSObject elem : array) { + if(elem == null) { + if(obj == null) + return true; + continue; + } if (elem.equals(nso)) { return true; } @@ -197,6 +200,8 @@ public class NSArray extends NSObject { @Override public boolean equals(Object obj) { + if(obj == null) + return false; if(obj.getClass().equals(NSArray.class)) { return Arrays.equals(((NSArray) obj).getArray(), this.array); } else { diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSDate.java b/third_party/java/dd_plist/java/com/dd/plist/NSDate.java index 5fb11f8f88..0f4246cdd8 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/NSDate.java +++ b/third_party/java/dd_plist/java/com/dd/plist/NSDate.java @@ -96,9 +96,20 @@ public class NSDate extends NSObject { * * @param bytes The date bytes */ - public NSDate(byte[] bytes) { + public NSDate(byte[] bytes){ + this(bytes, 0, bytes.length); + } + + /** + * Creates a date from its binary representation. + * + * @param bytes byte array with all information + * @param startIndex int with the starting index of the date + * @param endIndex int with the end index of the date + */ + public NSDate(byte[] bytes, final int startIndex, final int endIndex) { //dates are 8 byte big-endian double, seconds since the epoch - date = new Date(EPOCH + (long) (1000 * BinaryPropertyListParser.parseDouble(bytes))); + date = new Date(EPOCH + (long) (1000 * BinaryPropertyListParser.parseDouble(bytes, startIndex, endIndex))); } /** diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java b/third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java index 5d432ad1a7..a193a80e0c 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java +++ b/third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java @@ -35,7 +35,7 @@ import java.util.Set; /** * A NSDictionary is a collection of keys and values, essentially a Hashtable. * The keys are simple Strings whereas the values can be any kind of NSObject. - *

+ * * You can access the keys through the function allKeys(). Access * to the objects stored for each key is given through the function * objectoForKey(String key). @@ -148,6 +148,8 @@ public class NSDictionary extends NSObject implements Map { * or null, if no value was associated to it. */ public NSObject put(String key, NSObject obj) { + if(key == null) + return null; if(obj == null) return dict.get(key); return dict.put(key, obj); @@ -155,7 +157,7 @@ public class NSDictionary extends NSObject implements Map { /** * Puts a new key-value pair into this dictionary. - * If the value is null, no operation will be performed on the dictionary. + * If key or value are null, no operation will be performed on the dictionary. * * @param key The key. * @param obj The value. Supported object types are numbers, byte-arrays, dates, strings and arrays or sets of those. @@ -163,41 +165,9 @@ public class NSDictionary extends NSObject implements Map { * or null, if no value was associated to it. */ public NSObject put(String key, Object obj) { - if(obj == null) - return dict.get(key); return put(key, NSObject.wrap(obj)); } - /** - * Puts a new key-value pair into this dictionary. - * - * @param key The key. - * @param obj The value. - */ - public NSObject put(String key, long obj) { - return put(key, new NSNumber(obj)); - } - - /** - * Puts a new key-value pair into this dictionary. - * - * @param key The key. - * @param obj The value. - */ - public NSObject put(String key, double obj) { - return put(key, new NSNumber(obj)); - } - - /** - * Puts a new key-value pair into this dictionary. - * - * @param key The key. - * @param obj The value. - */ - public NSObject put(String key, boolean obj) { - return put(key, new NSNumber(obj)); - } - /** * Removes a key-value pair from this dictionary. * diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSNumber.java b/third_party/java/dd_plist/java/com/dd/plist/NSNumber.java index 9baf6f5dec..fab7d283a9 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/NSNumber.java +++ b/third_party/java/dd_plist/java/com/dd/plist/NSNumber.java @@ -62,19 +62,34 @@ public class NSNumber extends NSObject implements Comparable { * Parses integers and real numbers from their binary representation. * Note: real numbers are not yet supported. * - * @param bytes The binary representation + * @param bytes The binary representation of only this number * @param type The type of number * @see #INTEGER * @see #REAL */ - public NSNumber(byte[] bytes, int type) { + public NSNumber(byte[] bytes, int type){ + this(bytes, 0, bytes.length, type); + } + + /** + * Parses integers and real numbers from their binary representation. + * Note: real numbers are not yet supported. + * + * @param bytes array of bytes that contains this number's binary representation + * @param startIndex int with the position where to start reading from the byte array + * @param endIndex int with the position where to end reading from the byte array + * @param type The type of number + * @see #INTEGER + * @see #REAL + */ + public NSNumber(byte[] bytes, final int startIndex, final int endIndex, final int type){ switch (type) { case INTEGER: { - doubleValue = longValue = BinaryPropertyListParser.parseLong(bytes); + doubleValue = longValue = BinaryPropertyListParser.parseLong(bytes, startIndex, endIndex); break; } case REAL: { - doubleValue = BinaryPropertyListParser.parseDouble(bytes); + doubleValue = BinaryPropertyListParser.parseDouble(bytes, startIndex, endIndex); longValue = Math.round(doubleValue); break; } @@ -204,7 +219,7 @@ public class NSNumber extends NSObject implements Comparable { /** * The number's boolean value. * - * @return true if the value is true or non-zero, false otherwise. + * @return true if the value is true or non-zero, false otherwise. */ public boolean boolValue() { if (type == BOOLEAN) diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSObject.java b/third_party/java/dd_plist/java/com/dd/plist/NSObject.java index 6618fa13b7..b2c3cf0054 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/NSObject.java +++ b/third_party/java/dd_plist/java/com/dd/plist/NSObject.java @@ -77,6 +77,8 @@ public abstract class NSObject { * Generates the binary representation of the object. * * @param out The output stream to serialize the object to. + * @throws java.io.IOException When an IO error occurs while writing to the stream or the object structure contains + * data that cannot be saved. */ abstract void toBinary(BinaryPropertyListWriter out) throws IOException; @@ -233,7 +235,7 @@ public abstract class NSObject { */ public static NSObject wrap(Object o) { if(o == null) - throw new NullPointerException("A null object cannot be wrapped as a NSObject"); + return null; if(o instanceof NSObject) return (NSObject)o; diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSSet.java b/third_party/java/dd_plist/java/com/dd/plist/NSSet.java index 2528951978..6e43151a9f 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/NSSet.java +++ b/third_party/java/dd_plist/java/com/dd/plist/NSSet.java @@ -30,8 +30,6 @@ import java.util.*; * A set is an interface to an unordered collection of objects. * This implementation uses a LinkedHashSet or TreeSetas the underlying * data structure. - *

- * Warning: Sets cannot yet be used for saving in binary property lists, as binary property list format v1+ is required to save them. * * @author Daniel Dreibrodt * @see LinkedHashSet @@ -80,6 +78,7 @@ public class NSSet extends NSObject { /** * Create a set and fill it with the given objects. * + * @param ordered Indicates whether the created set should be ordered or unordered. * @param objects The objects to populate the set. * @see java.util.LinkedHashSet * @see java.util.TreeSet diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSString.java b/third_party/java/dd_plist/java/com/dd/plist/NSString.java index d692bbfc44..e5f5e6c316 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/NSString.java +++ b/third_party/java/dd_plist/java/com/dd/plist/NSString.java @@ -43,11 +43,25 @@ public class NSString extends NSObject implements Comparable { * * @param bytes The binary representation. * @param encoding The encoding of the binary representation, the name of a supported charset. - * @throws UnsupportedEncodingException - * @see java.lang.String + * @throws UnsupportedEncodingException When the given encoding is not supported by the JRE. + * @see java.lang.String#String(byte[], String) */ public NSString(byte[] bytes, String encoding) throws UnsupportedEncodingException { - content = new String(bytes, encoding); + this(bytes, 0, bytes.length, encoding); + } + + /** + * Creates an NSString from its binary representation. + * + * @param bytes The binary representation. + * @param startIndex int with the index where to start (offset) + * @param endIndex int with the index where to stop reading (offset + string length) + * @param encoding The encoding of the binary representation, the name of a supported charset. + * @throws UnsupportedEncodingException When the given encoding is not supported by the JRE. + * @see java.lang.String#String(byte[], String) + */ + public NSString(byte[] bytes, final int startIndex, final int endIndex, String encoding) throws UnsupportedEncodingException { + content = new String(bytes, startIndex, endIndex - startIndex, encoding); } /** diff --git a/third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java b/third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java index 4e681446b8..0f307dcada 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java +++ b/third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java @@ -38,7 +38,7 @@ import java.text.ParseException; /** * This class provides methods to parse property lists. It can handle files, * input streams and byte arrays. All known property list formats are supported. - *

+ * * This class also provides methods to save and convert property lists. * * @author Daniel Dreibrodt @@ -51,6 +51,8 @@ public class PropertyListParser { private static final int TYPE_ERROR_BLANK = 10; private static final int TYPE_ERROR_UNKNOWN = 11; + private static final int READ_BUFFER_LENGTH = 2048; + /** * Prevent instantiation. */ @@ -88,6 +90,10 @@ public class PropertyListParser { private static int determineType(byte[] bytes) { //Skip any possible whitespace at the beginning of the file int offset = 0; + if(bytes.length >= 3 && (bytes[0] & 0xFF) == 0xEF && (bytes[1] & 0xFF) == 0xBB && (bytes[2] & 0xFF) == 0xBF) { + //Skip Unicode byte order mark (BOM) + offset += 3; + } while(offset < bytes.length && (bytes[offset] == ' ' || bytes[offset] == '\t' || bytes[offset] == '\r' || bytes[offset] == '\n' || bytes[offset] == '\f')) { offset++; } @@ -105,12 +111,17 @@ public class PropertyListParser { //Skip any possible whitespace at the beginning of the file byte[] magicBytes = new byte[8]; int b; + long index = -1; + boolean bom = false; do { if(is.markSupported()) is.mark(16); b = is.read(); + index++; + //Check if we are reading the Unicode byte order mark (BOM) and skip it + bom = index < 3 && ((index == 0 && b == 0xEF) || (bom && ((index == 1 && b == 0xBB) || (index == 2 && b == 0xBF)))); } - while(b != -1 && b == ' ' || b == '\t' || b == '\r' || b == '\n' || b == '\f'); + while(b != -1 && b == ' ' || b == '\t' || b == '\r' || b == '\n' || b == '\f' || bom); magicBytes[0] = (byte)b; int read = is.read(magicBytes, 1, 7); int type = determineType(new String(magicBytes, 0, read)); @@ -124,12 +135,14 @@ public class PropertyListParser { * a maximum count. * * @param in The InputStream pointing to the data that should be stored in the array. + * @return An array containing all bytes that were read from the input stream. + * @throws java.io.IOException When an IO error while reading from the input stream. */ protected static byte[] readAll(InputStream in) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] buf = new byte[512]; + byte[] buf = new byte[READ_BUFFER_LENGTH]; int read; - while ((read = in.read(buf)) > 0) { + while ((read = in.read(buf, 0, READ_BUFFER_LENGTH)) != -1) { outputStream.write(buf, 0, read); } return outputStream.toByteArray(); @@ -140,7 +153,12 @@ public class PropertyListParser { * * @param filePath Path to the property list file. * @return The root object in the property list. This is usually a NSDictionary but can also be a NSArray. - * @throws Exception If an error occurred while parsing. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static NSObject parse(String filePath) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException { return parse(new File(filePath)); @@ -151,7 +169,12 @@ public class PropertyListParser { * * @param f The property list file. * @return The root object in the property list. This is usually a NSDictionary but can also be a NSArray. - * @throws Exception If an error occurred while parsing. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static NSObject parse(File f) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException { FileInputStream fis = new FileInputStream(f); @@ -174,7 +197,12 @@ public class PropertyListParser { * * @param bytes The property list data as a byte array. * @return The root object in the property list. This is usually a NSDictionary but can also be a NSArray. - * @throws Exception If an error occurred while parsing. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the byte array. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static NSObject parse(byte[] bytes) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException { switch(determineType(bytes)) { @@ -194,7 +222,12 @@ public class PropertyListParser { * * @param is The InputStream delivering the property list data. * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. - * @throws Exception If an error occurred while parsing. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the input stream. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static NSObject parse(InputStream is) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException { return parse(readAll(is)); @@ -210,7 +243,8 @@ public class PropertyListParser { public static void saveAsXML(NSObject root, File out) throws IOException { File parent = out.getParentFile(); if (!parent.exists()) - parent.mkdirs(); + if(!parent.mkdirs()) + throw new IOException("The output directory does not exist and could not be created."); FileOutputStream fous = new FileOutputStream(out); saveAsXML(root, fous); fous.close(); @@ -234,7 +268,13 @@ public class PropertyListParser { * * @param in The source file. * @param out The target file. - * @throws Exception When an error occurs during parsing or converting. + * + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static void convertToXml(File in, File out) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException { NSObject root = parse(in); @@ -251,7 +291,8 @@ public class PropertyListParser { public static void saveAsBinary(NSObject root, File out) throws IOException { File parent = out.getParentFile(); if (!parent.exists()) - parent.mkdirs(); + if(!parent.mkdirs()) + throw new IOException("The output directory does not exist and could not be created."); BinaryPropertyListWriter.write(out, root); } @@ -271,7 +312,12 @@ public class PropertyListParser { * * @param in The source file. * @param out The target file. - * @throws Exception When an error occurs during parsing or converting. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static void convertToBinary(File in, File out) throws IOException, ParserConfigurationException, ParseException, SAXException, PropertyListFormatException { NSObject root = parse(in); @@ -288,7 +334,8 @@ public class PropertyListParser { public static void saveAsASCII(NSDictionary root, File out) throws IOException { File parent = out.getParentFile(); if (!parent.exists()) - parent.mkdirs(); + if(!parent.mkdirs()) + throw new IOException("The output directory does not exist and could not be created."); OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "ASCII"); w.write(root.toASCIIPropertyList()); w.close(); @@ -312,7 +359,12 @@ public class PropertyListParser { * * @param in The source file. * @param out The target file. - * @throws Exception When an error occurs during parsing or converting. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static void convertToASCII(File in, File out) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException { NSObject root = parse(in); @@ -338,7 +390,8 @@ public class PropertyListParser { public static void saveAsGnuStepASCII(NSDictionary root, File out) throws IOException { File parent = out.getParentFile(); if (!parent.exists()) - parent.mkdirs(); + if(!parent.mkdirs()) + throw new IOException("The output directory does not exist and could not be created."); OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "ASCII"); w.write(root.toGnuStepASCIIPropertyList()); w.close(); @@ -354,7 +407,8 @@ public class PropertyListParser { public static void saveAsGnuStepASCII(NSArray root, File out) throws IOException { File parent = out.getParentFile(); if (!parent.exists()) - parent.mkdirs(); + if(!parent.mkdirs()) + throw new IOException("The output directory does not exist and could not be created."); OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "ASCII"); w.write(root.toGnuStepASCIIPropertyList()); w.close(); @@ -365,7 +419,12 @@ public class PropertyListParser { * * @param in The source file. * @param out The target file. - * @throws Exception When an error occurs during parsing or converting. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static void convertToGnuStepASCII(File in, File out) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException { NSObject root = parse(in); diff --git a/third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java b/third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java index 14776ea0b8..6fcb7f9315 100644 --- a/third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java +++ b/third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java @@ -55,8 +55,8 @@ public class XMLPropertyListParser { private static DocumentBuilderFactory docBuilderFactory = null; /** - * Initialize the document builder factory so that it can be reuused and does not need to - * be reinitialized for each new parsing. + * Initialize the document builder factory so that it can be reused and does not need to + * be reinitialized for each parse action. */ private static synchronized void initDocBuilderFactory() { docBuilderFactory = DocumentBuilderFactory.newInstance(); @@ -69,6 +69,8 @@ public class XMLPropertyListParser { * As DocumentBuilders are not thread-safe a new DocBuilder is generated for each request. * * @return A new DocBuilder that can parse property lists w/o an internet connection. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. */ private static synchronized DocumentBuilder getDocBuilder() throws ParserConfigurationException { if (docBuilderFactory == null) @@ -92,24 +94,34 @@ public class XMLPropertyListParser { * Parses a XML property list file. * * @param f The XML property list file. - * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray. - * @throws Exception When an error occurs during parsing. + * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. * @see javax.xml.parsers.DocumentBuilder#parse(java.io.File) + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ - public static NSObject parse(File f) throws ParseException, IOException, PropertyListFormatException, SAXException, ParserConfigurationException { + public static NSObject parse(File f) throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException { DocumentBuilder docBuilder = getDocBuilder(); Document doc = docBuilder.parse(f); - return parseDocument(doc); + return parse(doc); } /** * Parses a XML property list from a byte array. * * @param bytes The byte array containing the property list's data. - * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray. - * @throws Exception When an error occurs during parsing. + * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static NSObject parse(final byte[] bytes) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException { ByteArrayInputStream bis = new ByteArrayInputStream(bytes); @@ -120,26 +132,33 @@ public class XMLPropertyListParser { * Parses a XML property list from an input stream. * * @param is The input stream pointing to the property list's data. - * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray. - * @throws Exception When an error occurs during parsing. + * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray. * @see javax.xml.parsers.DocumentBuilder#parse(java.io.InputStream) + * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list + * could not be created. This should not occur. + * @throws java.io.IOException If any IO error occurs while reading the file. + * @throws org.xml.sax.SAXException If any parse error occurs. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ public static NSObject parse(InputStream is) throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException { DocumentBuilder docBuilder = getDocBuilder(); Document doc = docBuilder.parse(is); - return parseDocument(doc); + return parse(doc); } /** - * Parses the XML document by generating the appropriate NSObjects for each XML node. + * Parses a property list from an XML document. * * @param doc The XML document. * @return The root NSObject of the property list contained in the XML document. - * @throws Exception If an error occured during parsing. + * @throws java.io.IOException If any IO error occurs while reading the file. + * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format. + * @throws java.text.ParseException If a date string could not be parsed. */ - private static NSObject parseDocument(Document doc) throws PropertyListFormatException, IOException, ParseException { + public static NSObject parse(Document doc) throws PropertyListFormatException, IOException, ParseException { DocumentType docType = doc.getDoctype(); if (docType == null) { if (!doc.getDocumentElement().getNodeName().equals("plist")) { @@ -174,7 +193,8 @@ public class XMLPropertyListParser { * * @param n The XML node. * @return The corresponding NSObject. - * @throws Exception If an error occured during parsing the node. + * @throws java.io.IOException If any IO error occurs while parsing a Base64 encoded NSData object. + * @throws java.text.ParseException If a date string could not be parsed. */ private static NSObject parseObject(Node n) throws ParseException, IOException { String type = n.getNodeName(); @@ -219,7 +239,7 @@ public class XMLPropertyListParser { * Returns all element nodes that are contained in a list of nodes. * * @param list The list of nodes to search. - * @return The sublist containing only nodes representing actual elements. + * @return The sub-list containing only nodes representing actual elements. */ private static List filterElementNodes(NodeList list) { List result = new ArrayList(list.getLength()); -- cgit v1.2.3