diff --git a/plist-cil/BinaryPropertyListParser.cs b/plist-cil/BinaryPropertyListParser.cs index d2f0cdf..579fc9e 100644 --- a/plist-cil/BinaryPropertyListParser.cs +++ b/plist-cil/BinaryPropertyListParser.cs @@ -304,7 +304,7 @@ namespace Claunia.PropertyList int length = lenAndoffset[0]; int contentOffset = lenAndoffset[1]; - NSSet set = new NSSet(); + NSSet set = new NSSet(true); for (int i = 0; i < length; i++) { int objRef = (int) ParseUnsignedInt(CopyOfRange(bytes, offset + contentOffset + i * objectRefSize, diff --git a/plist-cil/BinaryPropertyListWriter.cs b/plist-cil/BinaryPropertyListWriter.cs new file mode 100644 index 0000000..3cd655f --- /dev/null +++ b/plist-cil/BinaryPropertyListWriter.cs @@ -0,0 +1,301 @@ +// plist-cil - An open source library to parse and generate property lists for .NET +// Copyright (C) 2015 Natalia Portillo +// +// This code is based on: +// plist - An open source library to parse and generate property lists +// Copyright (C) 2014 Daniel Dreibrodt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +using System; +using System.IO; +using System.Collections.Generic; + +namespace Claunia.PropertyList +{ + /// + /// A BinaryPropertyListWriter is a helper class for writing out + /// binary property list files. It contains an output stream and + /// various structures for keeping track of which NSObjects have + /// already been serialized, and where they were put in the file. + /// + /// @author Keith Randall + public class BinaryPropertyListWriter + { + public const int VERSION_00 = 0; + public const int VERSION_10 = 10; + public const int VERSION_15 = 15; + public const int VERSION_20 = 20; + + /// + /// Finds out the minimum binary property list format version that + /// can be used to save the given NSObject tree. + /// + /// Version code + /// Object root. + private static int GetMinimumRequiredVersion(NSObject root) { + int minVersion = VERSION_00; + if (root == null) { + minVersion = VERSION_10; + } + if (root is NSDictionary) { + NSDictionary dict = (NSDictionary) root; + foreach (NSObject o in dict.GetDictionary().Values) { + int v = GetMinimumRequiredVersion(o); + if (v > minVersion) + minVersion = v; + } + } else if (root is NSArray) { + NSArray array = (NSArray) root; + foreach (NSObject o in array.GetArray()) { + int v = GetMinimumRequiredVersion(o); + if (v > minVersion) + minVersion = v; + } + } else if (root is NSSet) { + //Sets are only allowed in property lists v1+ + minVersion = VERSION_10; + NSSet set = (NSSet) root; + foreach (NSObject o in set.AllObjects()) { + int v = GetMinimumRequiredVersion(o); + if (v > minVersion) + minVersion = v; + } + } + return minVersion; + } + + /// + /// Writes a binary plist file with the given object as the root. + /// + /// the file to write to + /// the source of the data to write to the file + /// + public static void Write(FileInfo file, NSObject root) { + FileStream fous = file.OpenWrite(); + Write(fous, root); + fous.Close(); + } + + /// + /// Writes a binary plist serialization of the given object as the root. + /// + /// the stream to write to + /// the source of the data to write to the stream + /// + public static void Write(Stream outStream, NSObject root) { + int minVersion = GetMinimumRequiredVersion(root); + if (minVersion > VERSION_00) { + string versionString = ((minVersion == VERSION_10) ? "v1.0" : ((minVersion == VERSION_15) ? "v1.5" : ((minVersion == VERSION_20) ? "v2.0" : "v0.0"))); + throw new IOException("The given property list structure cannot be saved. " + + "The required version of the binary format (" + versionString + ") is not yet supported."); + } + BinaryPropertyListWriter w = new BinaryPropertyListWriter(outStream, minVersion); + w.Write(root); + } + + /// + /// Writes a binary plist serialization of the given object as the root + /// into a byte array. + /// + /// The byte array containing the serialized property list + /// The root object of the property list + /// + public static byte[] WriteToArray(NSObject root) { + MemoryStream bout = new MemoryStream(); + Write(bout, root); + return bout.ToArray(); + } + + private int version = VERSION_00; + + // raw output stream to result file + private Stream outStream; + + // # of bytes written so far + private long count; + + // map from object to its ID + private Dictionary idMap = new Dictionary(); + private int idSizeInBytes; + + /// + /// Creates a new binary property list writer + /// + /// The output stream into which the binary property list will be written + /// If an error occured while writing to the stream + BinaryPropertyListWriter(Stream outStr) { + outStream = outStr; + } + + BinaryPropertyListWriter(Stream outStr, int version) { + this.version = version; + outStream = outStr; + } + + void Write(NSObject root) { + // magic bytes + Write(new byte[]{(byte)'b', (byte)'p', (byte)'l', (byte)'i', (byte)'s', (byte)'t'}); + + //version + switch (version) { + case VERSION_00: { + Write(new byte[]{(byte)'0', (byte)'0'}); + break; + } + case VERSION_10: { + Write(new byte[]{(byte)'1', (byte)'0'}); + break; + } + case VERSION_15: { + Write(new byte[]{(byte)'1', (byte)'5'}); + break; + } + case VERSION_20: { + Write(new byte[]{(byte)'2', (byte)'0'}); + break; + } + } + + // assign IDs to all the objects. + root.AssignIDs(this); + + idSizeInBytes = ComputeIdSizeInBytes(idMap.Count); + + // offsets of each object, indexed by ID + long[] offsets = new long[idMap.Count]; + + // write each object, save offset + foreach (KeyValuePair entry in idMap) { + NSObject obj = entry.Key; + int id = entry.Value; + offsets[id] = count; + if (obj == null) { + Write(0x00); + } else { + obj.ToBinary(this); + } + } + + // write offset table + long offsetTableOffset = count; + int offsetSizeInBytes = ComputeOffsetSizeInBytes(count); + foreach (long offset in offsets) { + WriteBytes(offset, offsetSizeInBytes); + } + + if (version != VERSION_15) { + // write trailer + // 6 null bytes + Write(new byte[6]); + // size of an offset + Write(offsetSizeInBytes); + // size of a ref + Write(idSizeInBytes); + // number of objects + WriteLong(idMap.Count); + // top object + int rootID; + idMap.TryGetValue(root, out rootID); + WriteLong(rootID); + // offset table offset + WriteLong(offsetTableOffset); + } + + outStream.Flush(); + } + + internal void AssignID(NSObject obj) { + if (!idMap.ContainsKey(obj)) { + idMap.Add(obj, idMap.Count); + } + } + + internal int GetID(NSObject obj) { + int ID; + idMap.TryGetValue(obj, out ID); + return ID; + } + + private static int ComputeIdSizeInBytes(int numberOfIds) { + if (numberOfIds < 256) return 1; + if (numberOfIds < 65536) return 2; + return 4; + } + + private int ComputeOffsetSizeInBytes(long maxOffset) { + if (maxOffset < 256) return 1; + if (maxOffset < 65536) return 2; + if (maxOffset < 4294967296L) return 4; + return 8; + } + + internal void WriteIntHeader(int kind, int value) { + if (value <= 0) + throw new ArgumentException("value must be greater than 0", "value"); + + if (value < 15) { + Write((kind << 4) + value); + } else if (value < 256) { + Write((kind << 4) + 15); + Write(0x10); + WriteBytes(value, 1); + } else if (value < 65536) { + Write((kind << 4) + 15); + Write(0x11); + WriteBytes(value, 2); + } else { + Write((kind << 4) + 15); + Write(0x12); + WriteBytes(value, 4); + } + } + + internal void Write(int b) { + byte[] bBytes= new byte[1]; + bBytes[0] = (byte)b; + outStream.Write(bBytes, 0, 1); + count++; + } + + internal void Write(byte[] bytes) { + outStream.Write(bytes, 0, bytes.Length); + count += bytes.Length; + } + + internal void WriteBytes(long value, int bytes) { + // write low-order bytes big-endian style + for (int i = bytes - 1; i >= 0; i--) { + Write((int) (value >> (8 * i))); + } + } + + internal void WriteID(int id) { + WriteBytes(id, idSizeInBytes); + } + + internal void WriteLong(long value) { + WriteBytes(value, 8); + } + + internal void WriteDouble(double value) { + WriteLong(BitConverter.DoubleToInt64Bits(value)); + } + } +} + diff --git a/plist-cil/ChangeLog b/plist-cil/ChangeLog index d55b3ba..4a9ec5a 100644 --- a/plist-cil/ChangeLog +++ b/plist-cil/ChangeLog @@ -1,3 +1,23 @@ +2015-02-19 Natalia Portillo + + * UID.cs: + * NSData.cs: + * NSDate.cs: + * NSArray.cs: + * NSNumber.cs: + * NSString.cs: + * NSObject.cs: + * NSDictionary.cs: + * plist-cil.csproj: + * PropertyListParser.cs: + * BinaryPropertyListWriter.cs: + Implement BinaryPropertyListWriter. + + * NSSet.cs: + * BinaryPropertyListParser.cs: + Implement BinaryPropertyListWriter. + Add way to make ordered NSSet. + 2015-02-19 Natalia Portillo * NSDate.cs: diff --git a/plist-cil/NSArray.cs b/plist-cil/NSArray.cs index 50ab7e1..da6f447 100644 --- a/plist-cil/NSArray.cs +++ b/plist-cil/NSArray.cs @@ -235,22 +235,19 @@ namespace Claunia.PropertyList xml.Append(""); } - // TODO: Implement BinaryPropertyListWriter - /* - override void assignIDs(BinaryPropertyListWriter out) { - super.assignIDs(out); - for (NSObject obj : array) { - obj.assignIDs(out); + internal override void AssignIDs(BinaryPropertyListWriter outPlist) { + base.AssignIDs(outPlist); + foreach (NSObject obj in array) { + obj.AssignIDs(outPlist); } } - override void toBinary(BinaryPropertyListWriter out) throws IOException { - out.writeIntHeader(0xA, array.length); - for (NSObject obj : array) { - out.writeID(out.getID(obj)); + internal override void ToBinary(BinaryPropertyListWriter outPlist) { + outPlist.WriteIntHeader(0xA, array.Length); + foreach (NSObject obj in array) { + outPlist.WriteID(outPlist.GetID(obj)); } - }*/ - + } /// /// Generates a valid ASCII property list which has this NSArray as its diff --git a/plist-cil/NSData.cs b/plist-cil/NSData.cs index bc0f2cc..4b39d87 100644 --- a/plist-cil/NSData.cs +++ b/plist-cil/NSData.cs @@ -137,13 +137,10 @@ namespace Claunia.PropertyList xml.Append(""); } - // TODO: Implement BinaryPropertyListWriter - /* - @Override - void toBinary(BinaryPropertyListWriter out) throws IOException { - out.writeIntHeader(0x4, bytes.length); - out.write(bytes); - }*/ + internal override void ToBinary(BinaryPropertyListWriter outPlist) { + outPlist.WriteIntHeader(0x4, bytes.Length); + outPlist.Write(bytes); + } internal override void ToASCII(StringBuilder ascii, int level) { Indent(ascii, level); diff --git a/plist-cil/NSDate.cs b/plist-cil/NSDate.cs index 8101150..225052d 100644 --- a/plist-cil/NSDate.cs +++ b/plist-cil/NSDate.cs @@ -133,12 +133,10 @@ namespace Claunia.PropertyList xml.Append(""); } - // TODO: ImplementBinaryPropertyListWriter - /* - public override void toBinary(BinaryPropertyListWriter out) throws IOException { - out.write(0x33); - out.writeDouble((date.getTime() - EPOCH) / 1000.0); - }*/ + internal override void ToBinary(BinaryPropertyListWriter outPlist) { + outPlist.Write(0x33); + outPlist.WriteDouble((date - EPOCH).TotalSeconds); + } /// /// Generates a string representation of the date. diff --git a/plist-cil/NSDictionary.cs b/plist-cil/NSDictionary.cs index f78fa03..3635137 100644 --- a/plist-cil/NSDictionary.cs +++ b/plist-cil/NSDictionary.cs @@ -268,26 +268,23 @@ namespace Claunia.PropertyList xml.Append(""); } - // TODO: BinaryPropertyListWriter - /* - override void assignIDs(BinaryPropertyListWriter out) { - super.assignIDs(out); - for (Map.Entry entry : dict.entrySet()) { - new NSString(entry.getKey()).assignIDs(out); - entry.getValue().assignIDs(out); + internal override void AssignIDs(BinaryPropertyListWriter outPlist) { + base.AssignIDs(outPlist); + foreach (KeyValuePair entry in dict) { + new NSString(entry.Key).AssignIDs(outPlist); + entry.Value.AssignIDs(outPlist); } } - override void toBinary(BinaryPropertyListWriter out) throws IOException { - out.writeIntHeader(0xD, dict.size()); - Set> entries = dict.entrySet(); - for (Map.Entry entry : entries) { - out.writeID(out.getID(new NSString(entry.getKey()))); + internal override void ToBinary(BinaryPropertyListWriter outPlist) { + outPlist.WriteIntHeader(0xD, dict.Count); + foreach (KeyValuePair entry in dict) { + outPlist.WriteID(outPlist.GetID(new NSString(entry.Key))); } - for (Map.Entry entry : entries) { - out.writeID(out.getID(entry.getValue())); + foreach (KeyValuePair entry in dict) { + outPlist.WriteID(outPlist.GetID(entry.Value)); } - }*/ + } /// /// Generates a valid ASCII property list which has this NSDictionary as its diff --git a/plist-cil/NSNumber.cs b/plist-cil/NSNumber.cs index bef7d22..fa9e41d 100644 --- a/plist-cil/NSNumber.cs +++ b/plist-cil/NSNumber.cs @@ -299,41 +299,38 @@ namespace Claunia.PropertyList } } - // TODO: Implement BinaryPropertyListWriter class - /* - @Override - void toBinary(BinaryPropertyListWriter out) throws IOException { - switch (type()) { + internal override void ToBinary(BinaryPropertyListWriter outPlist) { + switch (GetNSNumberType()) { case INTEGER: { - if (longValue() < 0) { - out.write(0x13); - out.writeBytes(longValue(), 8); - } else if (longValue() <= 0xff) { - out.write(0x10); - out.writeBytes(longValue(), 1); - } else if (longValue() <= 0xffff) { - out.write(0x11); - out.writeBytes(longValue(), 2); - } else if (longValue() <= 0xffffffffL) { - out.write(0x12); - out.writeBytes(longValue(), 4); + if (ToLong() < 0) { + outPlist.Write(0x13); + outPlist.WriteBytes(ToLong(), 8); + } else if (ToLong() <= 0xff) { + outPlist.Write(0x10); + outPlist.WriteBytes(ToLong(), 1); + } else if (ToLong() <= 0xffff) { + outPlist.Write(0x11); + outPlist.WriteBytes(ToLong(), 2); + } else if (ToLong() <= 0xffffffffL) { + outPlist.Write(0x12); + outPlist.WriteBytes(ToLong(), 4); } else { - out.write(0x13); - out.writeBytes(longValue(), 8); + outPlist.Write(0x13); + outPlist.WriteBytes(ToLong(), 8); } break; } case REAL: { - out.write(0x23); - out.writeDouble(doubleValue()); + outPlist.Write(0x23); + outPlist.WriteDouble(ToDouble()); break; } case BOOLEAN: { - out.write(boolValue() ? 0x09 : 0x08); + outPlist.Write(ToBool() ? 0x09 : 0x08); break; } } - }*/ + } internal override void ToASCII(StringBuilder ascii, int level) { Indent(ascii, level); diff --git a/plist-cil/NSObject.cs b/plist-cil/NSObject.cs index 497f7d4..d4ad3b4 100644 --- a/plist-cil/NSObject.cs +++ b/plist-cil/NSObject.cs @@ -70,18 +70,15 @@ namespace Claunia.PropertyList /// Assigns IDs to all the objects in this NSObject subtree. /// /// The writer object that handles the binary serialization. - // TODO: Port BinaryPropertyListWriter class - /* - void assignIDs(BinaryPropertyListWriter out) { - out.assignID(this); - }*/ + internal virtual void AssignIDs(BinaryPropertyListWriter outPlist) { + outPlist.AssignID(this); + } /// /// Generates the binary representation of the object. /// /// The output stream to serialize the object to. - // TODO: Port BinaryPropertyListWriter class - //abstract void toBinary(BinaryPropertyListWriter out); + internal abstract void ToBinary(BinaryPropertyListWriter outPlist); /// /// Generates a valid XML property list including headers using this object as root. diff --git a/plist-cil/NSSet.cs b/plist-cil/NSSet.cs index 6db621b..f9800bc 100644 --- a/plist-cil/NSSet.cs +++ b/plist-cil/NSSet.cs @@ -40,8 +40,7 @@ namespace Claunia.PropertyList { List set; - // No need for this. It's easier in C# to just follow NSSet unordered as-is - // private bool ordered = false; + private bool ordered = false; /// /// Creates an empty unordered set. @@ -67,6 +66,12 @@ namespace Claunia.PropertyList set = new TreeSet(); }*/ + public NSSet(bool ordered) { + this.ordered = ordered; + set = new List(); + } + + /// /// Create a set and fill it with the given objects. /// @@ -93,6 +98,13 @@ namespace Claunia.PropertyList set.addAll(Arrays.asList(objects)); }*/ + public NSSet(bool ordered, params NSObject[] objects) { + this.ordered = ordered; + set = new List(objects); + if (ordered) + set.Sort(); + } + /// /// Adds an object to the set. /// @@ -100,6 +112,8 @@ namespace Claunia.PropertyList [MethodImpl(MethodImplOptions.Synchronized)] public void AddObject(NSObject obj) { set.Add(obj); + if (ordered) + set.Sort(); } /// @@ -109,6 +123,8 @@ namespace Claunia.PropertyList [MethodImpl(MethodImplOptions.Synchronized)] public void RemoveObject(NSObject obj) { set.Remove(obj); + if (ordered) + set.Sort(); } /// @@ -247,6 +263,8 @@ namespace Claunia.PropertyList Indent(xml, level); xml.Append(""); xml.Append(NSObject.NEWLINE); + if (ordered) + set.Sort(); foreach (NSObject o in set) { o.ToXml(xml, level + 1); xml.Append(NSObject.NEWLINE); @@ -255,27 +273,24 @@ namespace Claunia.PropertyList xml.Append(""); } - // TODO: Implement BinaryPropertyListWriter - /* - @Override - void assignIDs(BinaryPropertyListWriter out) { - super.assignIDs(out); - for (NSObject obj : set) { - obj.assignIDs(out); + internal override void AssignIDs(BinaryPropertyListWriter outPlist) { + base.AssignIDs(outPlist); + foreach (NSObject obj in set) { + obj.AssignIDs(outPlist); } } - @Override - void toBinary(BinaryPropertyListWriter out) throws IOException { + internal override void ToBinary(BinaryPropertyListWriter outPlist) { if (ordered) { - out.writeIntHeader(0xB, set.size()); + set.Sort(); + outPlist.WriteIntHeader(0xB, set.Count); } else { - out.writeIntHeader(0xC, set.size()); + outPlist.WriteIntHeader(0xC, set.Count); } - for (NSObject obj : set) { - out.writeID(out.getID(obj)); + foreach (NSObject obj in set) { + outPlist.WriteID(outPlist.GetID(obj)); } - }*/ + } /// /// Returns the ASCII representation of this set. @@ -286,6 +301,8 @@ namespace Claunia.PropertyList /// The indentation level internal override void ToASCII(StringBuilder ascii, int level) { Indent(ascii, level); + if (ordered) + set.Sort(); NSObject[] array = AllObjects(); ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN); int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE); @@ -322,6 +339,8 @@ namespace Claunia.PropertyList /// The indentation level internal override void ToASCIIGnuStep(StringBuilder ascii, int level) { Indent(ascii, level); + if (ordered) + set.Sort(); NSObject[] array = AllObjects(); ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN); int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE); diff --git a/plist-cil/NSString.cs b/plist-cil/NSString.cs index 67f634c..da9b13c 100644 --- a/plist-cil/NSString.cs +++ b/plist-cil/NSString.cs @@ -151,37 +151,27 @@ namespace Claunia.PropertyList xml.Append(""); } - // TODO: Implement BinaryPropertyListWriter - /* - @Override - public void toBinary(BinaryPropertyListWriter out) throws IOException { - CharBuffer charBuf = CharBuffer.wrap(content); + internal override void ToBinary(BinaryPropertyListWriter outPlist) { int kind; - ByteBuffer byteBuf; - synchronized (NSString.class) { + byte[] byteBuf; + lock (typeof(NSString)) { if (asciiEncoder == null) - asciiEncoder = Charset.forName("ASCII").newEncoder(); - else - asciiEncoder.reset(); + asciiEncoder = Encoding.GetEncoding("ascii", EncoderExceptionFallback.ExceptionFallback, DecoderExceptionFallback.ExceptionFallback); - if (asciiEncoder.canEncode(charBuf)) { + try { kind = 0x5; // standard ASCII - byteBuf = asciiEncoder.encode(charBuf); - } else { + byteBuf = asciiEncoder.GetBytes(content); + } catch { if (utf16beEncoder == null) - utf16beEncoder = Charset.forName("UTF-16BE").newEncoder(); - else - utf16beEncoder.reset(); + utf16beEncoder = Encoding.BigEndianUnicode; kind = 0x6; // UTF-16-BE - byteBuf = utf16beEncoder.encode(charBuf); + byteBuf = utf16beEncoder.GetBytes(content); } } - byte[] bytes = new byte[byteBuf.remaining()]; - byteBuf.get(bytes); - out.writeIntHeader(kind, content.length()); - out.write(bytes); - }*/ + outPlist.WriteIntHeader(kind, content.Length); + outPlist.Write(byteBuf); + } internal override void ToASCII(StringBuilder ascii, int level) { Indent(ascii, level); diff --git a/plist-cil/PropertyListParser.cs b/plist-cil/PropertyListParser.cs index ee593c5..f174453 100644 --- a/plist-cil/PropertyListParser.cs +++ b/plist-cil/PropertyListParser.cs @@ -229,8 +229,7 @@ namespace Claunia.PropertyList string parent = outFile.DirectoryName; if (!Directory.Exists(parent)) Directory.CreateDirectory(parent); - // TODO: Implement BinaryPropertyListWriter - //BinaryPropertyListWriter.write(out, root); + BinaryPropertyListWriter.Write(outFile, root); } /// @@ -240,8 +239,7 @@ namespace Claunia.PropertyList /// The output stream. /// When an error occurs during the writing process. public static void SaveAsBinary(NSObject root, Stream outStream) { - // TODO: Implement BinaryPropertyListWriter - //BinaryPropertyListWriter.write(out, root); + //BinaryPropertyListWriter.write(outStream, root); } /// diff --git a/plist-cil/UID.cs b/plist-cil/UID.cs index a7f5156..1ef24ff 100644 --- a/plist-cil/UID.cs +++ b/plist-cil/UID.cs @@ -74,12 +74,10 @@ namespace Claunia.PropertyList xml.Append(""); } - // TODO: Implement BinaryPropertyListWriter - /* - void override toBinary(BinaryPropertyListWriter out) throws IOException { - out.write(0x80 + bytes.length - 1); - out.write(bytes); - }*/ + internal override void ToBinary(BinaryPropertyListWriter outPlist) { + outPlist.Write(0x80 + bytes.Length - 1); + outPlist.Write(bytes); + } internal override void ToASCII(StringBuilder ascii, int level) { Indent(ascii, level); diff --git a/plist-cil/plist-cil.csproj b/plist-cil/plist-cil.csproj index 1c4542a..0611829 100644 --- a/plist-cil/plist-cil.csproj +++ b/plist-cil/plist-cil.csproj @@ -46,6 +46,7 @@ +