aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/java
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2016-04-05 18:29:00 +0000
committerGravatar Lukacs Berki <lberki@google.com>2016-04-07 11:40:11 +0000
commit709984d829f7d84097e899b55fb573d777e427dc (patch)
tree029d867c9b8874048fa94dd550a448bc60ff9286 /third_party/java
parent0f86dc815c46f5bde00e42fc875ed0502a1fac44 (diff)
Upgrade dd_plist to version 1.17
Pair programmed with @matvore to reapply internal patches. -- MOS_MIGRATED_REVID=119071196
Diffstat (limited to 'third_party/java')
-rw-r--r--third_party/java/dd_plist/README6
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/Base64.java70
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java343
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java12
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/NSArray.java9
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/NSDate.java15
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java38
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/NSNumber.java25
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/NSObject.java4
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/NSSet.java3
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/NSString.java20
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java93
-rw-r--r--third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java52
13 files changed, 381 insertions, 309 deletions
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;
/**
* <p>Encodes and decodes to and from Base64 notation.</p>
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
- * <p/>
+ *
* <p>Example:</p>
- * <p/>
+ *
* <code>String encoded = Base64.encode( myByteArray );</code>
- * <br />
+ *
* <code>byte[] myByteArray = Base64.decode( encoded );</code>
- * <p/>
+ *
* <p>The <tt>options</tt> 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.</p>
- * <p/>
+ *
* <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,
* 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.</p>
- * <p/>
+ *
* <p>The constants defined in Base64 can be OR-ed together to combine options, so you
* might make a call like this:</p>
- * <p/>
+ *
* <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
* <p>to compress the data before encoding it and then making the output have newline characters.</p>
* <p>Also...</p>
* <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
- * <p/>
- * <p/>
- * <p/>
+ *
+ *
+ *
* <p>
* Change Log:
* </p>
+ *
* <ul>
* <li>v2.3.7 - Fixed subtle bug when base 64 input stream contained the
* value 01111111, which is an invalid base 64 character but should not
@@ -129,7 +130,7 @@ package com.dd.plist;
* Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
* for contributing the new Base64 dialects.
* </li>
- * <p/>
+ *
* <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
* some convenience methods for reading and writing to and from files.</li>
* <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
@@ -157,7 +158,7 @@ package com.dd.plist;
* <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
* <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
* </ul>
- * <p/>
+ *
* <p>
* 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.
- * <p/>
+ *
* <p>As of v 2.3, if the object
* cannot be serialized or there is another error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
* in retrospect that's a pretty poor way to handle it.</p>
- * <p/>
+ *
* 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.
- * <p/>
+ *
* <p>As of v 2.3, if the object
* cannot be serialized or there is another error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
* in retrospect that's a pretty poor way to handle it.</p>
- * <p/>
+ *
* The object is not GZip-compressed before being encoded.
- * <p/>
+ *
* Example options:<pre>
* GZIP: gzip-compresses object before encoding it.
* DO_BREAK_LINES: break lines at 76 characters
* </pre>
- * <p/>
+ *
* Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
- * <p/>
+ *
* Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
*
* @param serializableObject The object to encode
@@ -790,8 +791,8 @@ public class Base64 {
* Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
* <p>
* Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
- * <p/>
- * <p/>
+ *
+ *
* <p>As of v 2.3, if there is an error with the GZIP stream,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* 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.
- * <p/>
+ *
* <p>As of v 2.3, if there is an error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
@@ -855,8 +856,8 @@ public class Base64 {
* Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
* <p>
* Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
- * <p/>
- * <p/>
+ *
+ *
* <p>As of v 2.3, if there is an error with the GZIP stream,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* 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.
- * <p/>
+ *
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned false, but
@@ -1484,7 +1486,7 @@ public class Base64 {
/**
* Convenience method for decoding data to a file.
- * <p/>
+ *
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* 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.
- * <p/>
+ *
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* 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.
- * <p/>
+ *
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* 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.
- * <p/>
+ *
* Valid options:<pre>
* ENCODE or DECODE: Encode or Decode as data is read.
* DO_BREAK_LINES: break lines at 76 characters
- * (only meaningful when encoding)</i>
+ * (only meaningful when encoding)
* </pre>
- * <p/>
+ *
* Example: <code>new Base64.B64InputStream( in, Base64.DECODE )</code>
*
* @param in the <tt>java.io.InputStream</tt> 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.
- * <p/>
+ *
* Valid options:<pre>
* ENCODE or DECODE: Encode or Decode as data is read.
* DO_BREAK_LINES: don't break lines at 76 characters
- * (only meaningful when encoding)</i>
+ * (only meaningful when encoding)
* </pre>
- * <p/>
+ *
* Example: <code>new Base64.B64OutputStream( out, Base64.ENCODE )</code>
*
* @param out the <tt>java.io.B64OutputStream</tt> 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.
- * <p/>
+ *
* Parsing is done by calling the static <code>parse</code> 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
- * <a href="http://www.opensource.apple.com/source/CF/CF-744/CFBinaryPList.c">
+ * <a href="http://www.opensource.apple.com/source/CF/CF-855.17/CFBinaryPList.c">
* Apple's binary property list parser implementation</a>.
*
* @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.
- * <p/>
+ *
* You can access the keys through the function <code>allKeys()</code>. Access
* to the objects stored for each key is given through the function
* <code>objectoForKey(String key)</code>.
@@ -148,6 +148,8 @@ public class NSDictionary extends NSObject implements Map<String, NSObject> {
* 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<String, NSObject> {
/**
* 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,42 +165,10 @@ public class NSDictionary extends NSObject implements Map<String, NSObject> {
* 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.
*
* @param key The key
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<Object> {
* Parses integers and real numbers from their binary representation.
* <i>Note: real numbers are not yet supported.</i>
*
- * @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.
+ * <i>Note: real numbers are not yet supported.</i>
+ *
+ * @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<Object> {
/**
* The number's boolean value.
*
- * @return <code>true</code> if the value is true or non-zero, false</code> otherwise.
+ * @return <code>true</code> if the value is true or non-zero, <code>false</code> 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 <code>LinkedHashSet</code> or <code>TreeSet</code>as the underlying
* data structure.
- * <p/>
- * <b>Warning:</b> 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<Object> {
*
* @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.
- * <p/>
+ *
* 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<Node> filterElementNodes(NodeList list) {
List<Node> result = new ArrayList<Node>(list.getLength());