mirror of
https://github.com/claunia/plist-cil.git
synced 2025-12-16 19:14:26 +00:00
Code cleanup and refactor.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System.IO;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Attributes.Jobs;
|
||||
using System.IO;
|
||||
|
||||
namespace Claunia.PropertyList.Benchmark
|
||||
{
|
||||
@@ -8,7 +8,7 @@ namespace Claunia.PropertyList.Benchmark
|
||||
[MemoryDiagnoser]
|
||||
public class BinaryPropertyListParserBenchmarks
|
||||
{
|
||||
private byte[] data = null;
|
||||
byte[] data;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
@@ -19,7 +19,7 @@ namespace Claunia.PropertyList.Benchmark
|
||||
[Benchmark]
|
||||
public NSObject ReadLargePropertylistTest()
|
||||
{
|
||||
var nsObject = PropertyListParser.Parse(this.data);
|
||||
NSObject nsObject = PropertyListParser.Parse(data);
|
||||
return nsObject;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Claunia.PropertyList.Benchmark
|
||||
[MemoryDiagnoser]
|
||||
public class BinaryPropertyListWriterBenchmarks
|
||||
{
|
||||
private NSObject data = null;
|
||||
NSObject data;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
@@ -15,7 +15,6 @@ namespace Claunia.PropertyList.Benchmark
|
||||
data = PropertyListParser.Parse("plist.bin");
|
||||
}
|
||||
|
||||
|
||||
[Benchmark]
|
||||
public byte[] WriteLargePropertylistTest()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using BenchmarkDotNet.Running;
|
||||
using System;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
namespace Claunia.PropertyList.Benchmark
|
||||
{
|
||||
@@ -7,7 +7,7 @@ namespace Claunia.PropertyList.Benchmark
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var summary = BenchmarkRunner.Run<BinaryPropertyListParserBenchmarks>();
|
||||
Summary summary = BenchmarkRunner.Run<BinaryPropertyListParserBenchmarks>();
|
||||
summary = BenchmarkRunner.Run<BinaryPropertyListWriterBenchmarks>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,11 @@
|
||||
using Claunia.PropertyList;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
public class BinaryPropertyListWriterTests
|
||||
{
|
||||
[Fact]
|
||||
public void RoundtripTest()
|
||||
{
|
||||
byte[] data = File.ReadAllBytes("test-files/plist.bin");
|
||||
NSObject root = PropertyListParser.Parse(data);
|
||||
|
||||
using (MemoryStream actualOutput = new MemoryStream())
|
||||
using (Stream expectedOutput = File.OpenRead("test-files/plist.bin"))
|
||||
using (ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput))
|
||||
{
|
||||
BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream);
|
||||
writer.ReuseObjectIds = false;
|
||||
writer.Write(root);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Roundtrip2Test()
|
||||
{
|
||||
@@ -69,5 +53,21 @@ namespace plistcil.test
|
||||
writer.Write(root);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundtripTest()
|
||||
{
|
||||
byte[] data = File.ReadAllBytes("test-files/plist.bin");
|
||||
NSObject root = PropertyListParser.Parse(data);
|
||||
|
||||
using(MemoryStream actualOutput = new MemoryStream())
|
||||
using(Stream expectedOutput = File.OpenRead("test-files/plist.bin"))
|
||||
using(ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput))
|
||||
{
|
||||
BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream);
|
||||
writer.ReuseObjectIds = false;
|
||||
writer.Write(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,31 +22,62 @@
|
||||
// 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 Xunit;
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
public static class IssueTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes sure that binary data is line-wrapped correctly when being serialized, in a scenario
|
||||
/// where the binary data is not indented (no leading whitespace).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void TestIssue4()
|
||||
public static void RoundtripDataTest()
|
||||
{
|
||||
NSDictionary d = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue4.plist"));
|
||||
Assert.Equal("Kid\u2019s iPhone", ((NSString)d.ObjectForKey("Device Name")).ToString());
|
||||
string expected = File.ReadAllText(@"test-files/RoundtripBinary.plist");
|
||||
NSObject value = XmlPropertyListParser.Parse(new FileInfo(@"test-files/RoundtripBinary.plist"));
|
||||
string actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes sure that binary data is line-wrapped correctly when being serialized, in a scenario
|
||||
/// where the binary data is indented.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void RoundtripDataTest2()
|
||||
{
|
||||
string expected = File.ReadAllText(@"test-files/RoundtripBinaryIndentation.plist");
|
||||
NSObject value =
|
||||
XmlPropertyListParser.Parse(new FileInfo(@"test-files/RoundtripBinaryIndentation.plist"));
|
||||
string actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestIssue7()
|
||||
public static void RoundtripRealTest()
|
||||
{
|
||||
// also a test for issue 12
|
||||
// the issue4 test has a UTF-16-BE string in its binary representation
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/issue4.plist"));
|
||||
PropertyListParser.SaveAsBinary(x, new FileInfo("test-files/out-testIssue7.plist"));
|
||||
NSObject y = PropertyListParser.Parse(new FileInfo("test-files/out-testIssue7.plist"));
|
||||
Assert.True(x.Equals(y));
|
||||
string expected = File.ReadAllText(@"test-files/RoundtripReal.plist");
|
||||
NSObject value = XmlPropertyListParser.Parse(new FileInfo(@"test-files/RoundtripReal.plist"));
|
||||
string actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, false, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RoundtripTest()
|
||||
{
|
||||
string expected = File.ReadAllText(@"test-files/Roundtrip.plist");
|
||||
NSObject value = XmlPropertyListParser.Parse(new FileInfo(@"test-files/Roundtrip.plist"));
|
||||
string actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, false, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -68,26 +99,28 @@ namespace plistcil.test
|
||||
[Fact]
|
||||
public static void TestIssue21()
|
||||
{
|
||||
String x = ((NSString)PropertyListParser.Parse(new FileInfo("test-files/issue21.plist"))).ToString();
|
||||
string x = ((NSString)PropertyListParser.Parse(new FileInfo("test-files/issue21.plist"))).ToString();
|
||||
Assert.Equal("Lot&s of &persand&s and other escapable \"\'<>€ characters", x);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestIssue22()
|
||||
{
|
||||
NSDictionary x1 = ((NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue22-emoji.plist")));
|
||||
NSDictionary x2 = ((NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue22-emoji-xml.plist")));
|
||||
NSDictionary x1 = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue22-emoji.plist"));
|
||||
NSDictionary x2 =
|
||||
(NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue22-emoji-xml.plist"));
|
||||
PropertyListParser.SaveAsBinary(x1, new FileInfo("test-files/out-testIssue22.plist"));
|
||||
NSDictionary y1 = ((NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/out-testIssue22.plist")));
|
||||
NSDictionary y1 = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/out-testIssue22.plist"));
|
||||
PropertyListParser.SaveAsXml(x2, new FileInfo("test-files/out-testIssue22-xml.plist"));
|
||||
NSDictionary y2 = ((NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/out-testIssue22-xml.plist")));
|
||||
NSDictionary y2 =
|
||||
(NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/out-testIssue22-xml.plist"));
|
||||
Assert.True(x1.Equals(x2));
|
||||
Assert.True(x1.Equals(y1));
|
||||
Assert.True(x1.Equals(y2));
|
||||
Assert.True(x2.Equals(y1));
|
||||
Assert.True(x2.Equals(y2));
|
||||
|
||||
String emojiString = "Test Test, \uD83D\uDE30\u2754\uD83D\uDC4D\uD83D\uDC4E\uD83D\uDD25";
|
||||
string emojiString = "Test Test, \uD83D\uDE30\u2754\uD83D\uDC4D\uD83D\uDC4E\uD83D\uDD25";
|
||||
|
||||
Assert.Equal(emojiString, x1.ObjectForKey("emojiString").ToString());
|
||||
Assert.Equal(emojiString, x2.ObjectForKey("emojiString").ToString());
|
||||
@@ -115,10 +148,18 @@ namespace plistcil.test
|
||||
public static void TestIssue38()
|
||||
{
|
||||
NSDictionary dict = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue33.pbxproj"));
|
||||
NSObject fileRef = ((NSDictionary)((NSDictionary)dict.Get("objects")).Get("65541A9C16D13B8C00A968D5")).Get("fileRef");
|
||||
NSObject fileRef =
|
||||
((NSDictionary)((NSDictionary)dict.Get("objects")).Get("65541A9C16D13B8C00A968D5")).Get("fileRef");
|
||||
Assert.True(fileRef.Equals(new NSString("65541A9B16D13B8C00A968D5")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestIssue4()
|
||||
{
|
||||
NSDictionary d = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue4.plist"));
|
||||
Assert.Equal("Kid\u2019s iPhone", ((NSString)d.ObjectForKey("Device Name")).ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestIssue49()
|
||||
{
|
||||
@@ -126,65 +167,28 @@ namespace plistcil.test
|
||||
Assert.Empty(dict);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestIssue7()
|
||||
{
|
||||
// also a test for issue 12
|
||||
// the issue4 test has a UTF-16-BE string in its binary representation
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/issue4.plist"));
|
||||
PropertyListParser.SaveAsBinary(x, new FileInfo("test-files/out-testIssue7.plist"));
|
||||
NSObject y = PropertyListParser.Parse(new FileInfo("test-files/out-testIssue7.plist"));
|
||||
Assert.True(x.Equals(y));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestRealInResourceRule()
|
||||
{
|
||||
NSDictionary dict = (NSDictionary)XmlPropertyListParser.Parse(new FileInfo("test-files/ResourceRules.plist"));
|
||||
NSDictionary dict =
|
||||
(NSDictionary)XmlPropertyListParser.Parse(new FileInfo("test-files/ResourceRules.plist"));
|
||||
Assert.Single(dict);
|
||||
Assert.True(dict.ContainsKey("weight"));
|
||||
|
||||
var weight = dict["weight"].ToObject();
|
||||
object weight = dict["weight"].ToObject();
|
||||
Assert.IsType<double>(weight);
|
||||
Assert.Equal(10d, (double)weight);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RoundtripTest()
|
||||
{
|
||||
var expected = File.ReadAllText(@"test-files/Roundtrip.plist");
|
||||
var value = XmlPropertyListParser.Parse(new FileInfo(@"test-files/Roundtrip.plist"));
|
||||
var actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, false, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RoundtripRealTest()
|
||||
{
|
||||
var expected = File.ReadAllText(@"test-files/RoundtripReal.plist");
|
||||
var value = XmlPropertyListParser.Parse(new FileInfo(@"test-files/RoundtripReal.plist"));
|
||||
var actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, false, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes sure that binary data is line-wrapped correctly when being serialized, in a scenario
|
||||
/// where the binary data is not indented (no leading whitespace).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void RoundtripDataTest()
|
||||
{
|
||||
var expected = File.ReadAllText(@"test-files/RoundtripBinary.plist");
|
||||
var value = XmlPropertyListParser.Parse(new FileInfo(@"test-files/RoundtripBinary.plist"));
|
||||
var actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes sure that binary data is line-wrapped correctly when being serialized, in a scenario
|
||||
/// where the binary data is indented.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void RoundtripDataTest2()
|
||||
{
|
||||
var expected = File.ReadAllText(@"test-files/RoundtripBinaryIndentation.plist");
|
||||
var value = XmlPropertyListParser.Parse(new FileInfo(@"test-files/RoundtripBinaryIndentation.plist"));
|
||||
var actual = value.ToXmlPropertyList();
|
||||
|
||||
Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using Claunia.PropertyList;
|
||||
using System.Collections.Generic;
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
@@ -23,6 +19,29 @@ namespace plistcil.test
|
||||
Assert.False(array.Contains(2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the <see cref="NSArray.GetEnumerator" /> method.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void EnumeratorTest()
|
||||
{
|
||||
NSArray array = new NSArray();
|
||||
array.Add(0);
|
||||
array.Add(1);
|
||||
|
||||
IEnumerator<NSObject> enumerator = array.GetEnumerator();
|
||||
|
||||
Assert.Null(enumerator.Current);
|
||||
|
||||
Assert.True(enumerator.MoveNext());
|
||||
Assert.Equal(new NSNumber(0), enumerator.Current);
|
||||
|
||||
Assert.True(enumerator.MoveNext());
|
||||
Assert.Equal(new NSNumber(1), enumerator.Current);
|
||||
|
||||
Assert.False(enumerator.MoveNext());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the <see cref="NSArray.IndexOf(object)" /> method for .NET objects.
|
||||
/// </summary>
|
||||
@@ -68,28 +87,5 @@ namespace plistcil.test
|
||||
|
||||
Assert.Empty(array);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the <see cref="NSArray.GetEnumerator"/> method.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void EnumeratorTest()
|
||||
{
|
||||
NSArray array = new NSArray();
|
||||
array.Add(0);
|
||||
array.Add(1);
|
||||
|
||||
var enumerator = array.GetEnumerator();
|
||||
|
||||
Assert.Null(enumerator.Current);
|
||||
|
||||
Assert.True(enumerator.MoveNext());
|
||||
Assert.Equal(new NSNumber(0), enumerator.Current);
|
||||
|
||||
Assert.True(enumerator.MoveNext());
|
||||
Assert.Equal(new NSNumber(1), enumerator.Current);
|
||||
|
||||
Assert.False(enumerator.MoveNext());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
using Claunia.PropertyList;
|
||||
using System;
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
@@ -13,17 +9,17 @@ namespace plistcil.test
|
||||
[Fact]
|
||||
public static void ConstructorTest()
|
||||
{
|
||||
var actual = new NSDate("2000-01-01T00:00:00Z");
|
||||
var expected = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
NSDate actual = new NSDate("2000-01-01T00:00:00Z");
|
||||
DateTime expected = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
Assert.Equal(expected, actual.Date.ToUniversalTime());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MakeDateStringTest()
|
||||
{
|
||||
var date = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
var expected = "2000-01-01T00:00:00Z";
|
||||
var actual = NSDate.MakeDateString(date);
|
||||
DateTime date = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
string expected = "2000-01-01T00:00:00Z";
|
||||
string actual = NSDate.MakeDateString(date);
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
@@ -15,7 +8,7 @@ namespace plistcil.test
|
||||
[Fact]
|
||||
public static void NSNumberConstructorTest()
|
||||
{
|
||||
var number = new NSNumber("10032936613", NSNumber.INTEGER);
|
||||
NSNumber number = new NSNumber("10032936613", NSNumber.INTEGER);
|
||||
Assert.Equal(NSNumber.INTEGER, number.GetNSNumberType());
|
||||
Assert.Equal(10032936613, number.ToObject());
|
||||
}
|
||||
@@ -23,7 +16,7 @@ namespace plistcil.test
|
||||
[Fact]
|
||||
public static void NSNumberWithDecimalTest()
|
||||
{
|
||||
var number = new NSNumber("1360155352.748765", NSNumber.REAL);
|
||||
NSNumber number = new NSNumber("1360155352.748765", NSNumber.REAL);
|
||||
Assert.Equal("1360155352.748765", number.ToString());
|
||||
}
|
||||
|
||||
@@ -38,7 +31,7 @@ namespace plistcil.test
|
||||
[UseCulture("en-US")]
|
||||
public static void ParseNumberEnTest()
|
||||
{
|
||||
var number = new NSNumber("7200.000001");
|
||||
NSNumber number = new NSNumber("7200.000001");
|
||||
Assert.True(number.isReal());
|
||||
Assert.Equal(7200.000001d, number.ToDouble());
|
||||
}
|
||||
@@ -50,7 +43,7 @@ namespace plistcil.test
|
||||
// As seen in a real property list:
|
||||
// <key>TimeZoneOffsetFromUTC</key>
|
||||
// <real>7200.000000</real>
|
||||
var number = new NSNumber("7200.000001");
|
||||
NSNumber number = new NSNumber("7200.000001");
|
||||
Assert.True(number.isReal());
|
||||
Assert.Equal(7200.000001d, number.ToDouble());
|
||||
}
|
||||
@@ -62,7 +55,7 @@ namespace plistcil.test
|
||||
// As seen in a real property list:
|
||||
// <key>TimeZoneOffsetFromUTC</key>
|
||||
// <real>7200.000000</real>
|
||||
var number = new NSNumber("7200.000000", NSNumber.REAL);
|
||||
NSNumber number = new NSNumber("7200.000000", NSNumber.REAL);
|
||||
Assert.True(number.isReal());
|
||||
Assert.Equal(7200d, number.ToDouble());
|
||||
}
|
||||
@@ -74,7 +67,7 @@ namespace plistcil.test
|
||||
// As seen in a real property list:
|
||||
// <key>TimeZoneOffsetFromUTC</key>
|
||||
// <real>7200.000000</real>
|
||||
var number = new NSNumber("7200.000000", NSNumber.REAL);
|
||||
NSNumber number = new NSNumber("7200.000000", NSNumber.REAL);
|
||||
Assert.True(number.isReal());
|
||||
Assert.Equal(7200d, number.ToDouble());
|
||||
}
|
||||
|
||||
@@ -22,59 +22,29 @@
|
||||
// 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 Xunit;
|
||||
using Claunia.PropertyList;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
public static class ParseTest
|
||||
{
|
||||
/**
|
||||
* Test the xml reader/writer
|
||||
*/
|
||||
[Fact]
|
||||
public static void TestXml()
|
||||
static bool ArrayEquals(byte[] arrayA, byte[] arrayB)
|
||||
{
|
||||
// Parse an example plist file
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1.plist"));
|
||||
if(arrayA.Length == arrayB.Length)
|
||||
{
|
||||
for(int i = 0; i < arrayA.Length; i++)
|
||||
if(arrayA[i] != arrayB[i])
|
||||
return false;
|
||||
|
||||
// check the data in it
|
||||
NSDictionary d = (NSDictionary)x;
|
||||
Assert.True(d.Count == 5);
|
||||
Assert.Equal("valueA", ((NSString)d.ObjectForKey("keyA")).ToString());
|
||||
Assert.Equal("value&B", ((NSString)d.ObjectForKey("key&B")).ToString());
|
||||
Assert.True(((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 10, 21, 30, DateTimeKind.Utc)) ||
|
||||
((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 9, 21, 30, DateTimeKind.Utc)));
|
||||
Assert.True(ArrayEquals(((NSData)d.ObjectForKey("data")).Bytes,
|
||||
new byte[]{ 0x00, 0x00, 0x00, 0x04, 0x10, 0x41, 0x08, 0x20, (byte)0x82 }));
|
||||
NSArray a = (NSArray)d.ObjectForKey("array");
|
||||
Assert.True(a.Count == 4);
|
||||
Assert.True(a[0].Equals(new NSNumber(true)));
|
||||
Assert.True(a[1].Equals(new NSNumber(false)));
|
||||
Assert.True(a[2].Equals(new NSNumber(87)));
|
||||
Assert.True(a[3].Equals(new NSNumber(3.14159)));
|
||||
|
||||
// read/write it, make sure we get the same thing
|
||||
PropertyListParser.SaveAsXml(x, new FileInfo("test-files/out-testXml.plist"));
|
||||
NSObject y = PropertyListParser.Parse(new FileInfo("test-files/out-testXml.plist"));
|
||||
Assert.True(x.Equals(y));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the binary reader/writer.
|
||||
*/
|
||||
[Fact]
|
||||
public static void TestBinary()
|
||||
{
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1.plist"));
|
||||
|
||||
// save and load as binary
|
||||
PropertyListParser.SaveAsBinary(x, new FileInfo("test-files/out-testBinary.plist"));
|
||||
NSObject y = PropertyListParser.Parse(new FileInfo("test-files/out-testBinary.plist"));
|
||||
Assert.True(x.Equals(y));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,12 +83,12 @@ namespace plistcil.test
|
||||
Assert.Equal("valueA", ((NSString)d.ObjectForKey("keyA")).ToString());
|
||||
Assert.Equal("value&B", ((NSString)d.ObjectForKey("key&B")).ToString());
|
||||
|
||||
var actualDate = (NSDate)d.ObjectForKey("date");
|
||||
var expectedDate = new DateTime(2011, 11, 28, 9, 21, 30, DateTimeKind.Utc).ToLocalTime();
|
||||
NSDate actualDate = (NSDate)d.ObjectForKey("date");
|
||||
DateTime expectedDate = new DateTime(2011, 11, 28, 9, 21, 30, DateTimeKind.Utc).ToLocalTime();
|
||||
|
||||
Assert.Equal(actualDate.Date, expectedDate);
|
||||
Assert.True(ArrayEquals(((NSData)d.ObjectForKey("data")).Bytes,
|
||||
new byte[]{ 0x00, 0x00, 0x00, 0x04, 0x10, 0x41, 0x08, 0x20, (byte)0x82 }));
|
||||
new byte[] {0x00, 0x00, 0x00, 0x04, 0x10, 0x41, 0x08, 0x20, 0x82}));
|
||||
NSArray a = (NSArray)d.ObjectForKey("array");
|
||||
Assert.True(a.Count == 4);
|
||||
Assert.True(a[0].Equals(new NSString("YES")));
|
||||
@@ -128,22 +98,13 @@ namespace plistcil.test
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestGnuStepASCII()
|
||||
public static void testAsciiUtf8CharactersInQuotedString()
|
||||
{
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1-ascii-gnustep.plist"));
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test-ascii-utf8.plist"));
|
||||
NSDictionary d = (NSDictionary)x;
|
||||
Assert.True(d.Count == 5);
|
||||
Assert.Equal("valueA", ((NSString)d.ObjectForKey("keyA")).ToString());
|
||||
Assert.Equal("value&B", ((NSString)d.ObjectForKey("key&B")).ToString());
|
||||
Assert.True(((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 9, 21, 30, DateTimeKind.Utc).ToLocalTime()));
|
||||
Assert.True(ArrayEquals(((NSData)d.ObjectForKey("data")).Bytes,
|
||||
new byte[]{ 0x00, 0x00, 0x00, 0x04, 0x10, 0x41, 0x08, 0x20, (byte)0x82 }));
|
||||
NSArray a = (NSArray)d.ObjectForKey("array");
|
||||
Assert.True(a.Count == 4);
|
||||
Assert.True(a[0].Equals(new NSNumber(true)));
|
||||
Assert.True(a[1].Equals(new NSNumber(false)));
|
||||
Assert.True(a[2].Equals(new NSNumber(87)));
|
||||
Assert.True(a[3].Equals(new NSNumber(3.14159)));
|
||||
Assert.Equal(2, d.Count);
|
||||
Assert.Equal("JÔÖú@2x.jpg", d.ObjectForKey("path").ToString());
|
||||
Assert.Equal("QÔÖú@2x 啕.jpg", d.ObjectForKey("Key QÔÖª@2x 䌡").ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -162,6 +123,40 @@ namespace plistcil.test
|
||||
Assert.True(y.Equals(z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the binary reader/writer.
|
||||
*/
|
||||
[Fact]
|
||||
public static void TestBinary()
|
||||
{
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1.plist"));
|
||||
|
||||
// save and load as binary
|
||||
PropertyListParser.SaveAsBinary(x, new FileInfo("test-files/out-testBinary.plist"));
|
||||
NSObject y = PropertyListParser.Parse(new FileInfo("test-files/out-testBinary.plist"));
|
||||
Assert.True(x.Equals(y));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestGnuStepASCII()
|
||||
{
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1-ascii-gnustep.plist"));
|
||||
NSDictionary d = (NSDictionary)x;
|
||||
Assert.True(d.Count == 5);
|
||||
Assert.Equal("valueA", ((NSString)d.ObjectForKey("keyA")).ToString());
|
||||
Assert.Equal("value&B", ((NSString)d.ObjectForKey("key&B")).ToString());
|
||||
Assert.True(((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 9, 21, 30,
|
||||
DateTimeKind.Utc).ToLocalTime()));
|
||||
Assert.True(ArrayEquals(((NSData)d.ObjectForKey("data")).Bytes,
|
||||
new byte[] {0x00, 0x00, 0x00, 0x04, 0x10, 0x41, 0x08, 0x20, 0x82}));
|
||||
NSArray a = (NSArray)d.ObjectForKey("array");
|
||||
Assert.True(a.Count == 4);
|
||||
Assert.True(a[0].Equals(new NSNumber(true)));
|
||||
Assert.True(a[1].Equals(new NSNumber(false)));
|
||||
Assert.True(a[2].Equals(new NSNumber(87)));
|
||||
Assert.True(a[3].Equals(new NSNumber(3.14159)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestGnuStepASCIIWriting()
|
||||
{
|
||||
@@ -185,74 +180,73 @@ namespace plistcil.test
|
||||
double dbl = 32.0;
|
||||
DateTime date = new DateTime();
|
||||
string strg = "Hello World";
|
||||
byte[] bytes = new byte[] { (byte)0x00, (byte)0xAF, (byte)0xAF };
|
||||
Object[] array = new Object[] { bl, byt, shrt, i, lng, flt, dbl, date, strg, bytes };
|
||||
int[] array2 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3000 };
|
||||
List<Object> list = new List<Object>(array);
|
||||
byte[] bytes = {0x00, 0xAF, 0xAF};
|
||||
object[] array = {bl, byt, shrt, i, lng, flt, dbl, date, strg, bytes};
|
||||
int[] array2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3000};
|
||||
List<object> list = new List<object>(array);
|
||||
|
||||
Dictionary<string, Object> map = new Dictionary<string, Object>();
|
||||
Dictionary<string, object> map = new Dictionary<string, object>();
|
||||
map.Add("int", i);
|
||||
map.Add("long", lng);
|
||||
map.Add("date", date);
|
||||
|
||||
NSObject WrappedO = NSObject.Wrap((Object)bl);
|
||||
NSObject WrappedO = NSObject.Wrap((object)bl);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSNumber)));
|
||||
Assert.True(WrappedO.ToObject().Equals(bl));
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)byt);
|
||||
WrappedO = NSObject.Wrap((object)byt);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSNumber)));
|
||||
Assert.True((int)WrappedO.ToObject() == byt);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)shrt);
|
||||
WrappedO = NSObject.Wrap((object)shrt);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSNumber)));
|
||||
Assert.True((int)WrappedO.ToObject() == shrt);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)i);
|
||||
WrappedO = NSObject.Wrap((object)i);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSNumber)));
|
||||
Assert.True((int)WrappedO.ToObject() == i);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)lng);
|
||||
WrappedO = NSObject.Wrap((object)lng);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSNumber)));
|
||||
Assert.True((long)WrappedO.ToObject() == lng);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)flt);
|
||||
WrappedO = NSObject.Wrap((object)flt);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSNumber)));
|
||||
Assert.True((double)WrappedO.ToObject() == flt);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)dbl);
|
||||
WrappedO = NSObject.Wrap((object)dbl);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSNumber)));
|
||||
Assert.True((double)WrappedO.ToObject() == dbl);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)date);
|
||||
WrappedO = NSObject.Wrap(date);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSDate)));
|
||||
Assert.True(((DateTime)WrappedO.ToObject()).Equals(date));
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)strg);
|
||||
WrappedO = NSObject.Wrap(strg);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSString)));
|
||||
Assert.Equal(((string)WrappedO.ToObject()), strg);
|
||||
Assert.Equal((string)WrappedO.ToObject(), strg);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)bytes);
|
||||
WrappedO = NSObject.Wrap((object)bytes);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSData)));
|
||||
byte[] data = (byte[])WrappedO.ToObject();
|
||||
Assert.True(data.Length == bytes.Length);
|
||||
for (int x = 0; x < bytes.Length; x++)
|
||||
Assert.True(data[x] == bytes[x]);
|
||||
for(int x = 0; x < bytes.Length; x++) Assert.True(data[x] == bytes[x]);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)array);
|
||||
WrappedO = NSObject.Wrap((object)array);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSArray)));
|
||||
Object[] objArray = (Object[])WrappedO.ToObject();
|
||||
object[] objArray = (object[])WrappedO.ToObject();
|
||||
Assert.True(objArray.Length == array.Length);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)array2);
|
||||
WrappedO = NSObject.Wrap(array2);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSArray)));
|
||||
Assert.True(((NSArray)WrappedO).Count == array2.Length);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)list);
|
||||
WrappedO = NSObject.Wrap((object)list);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSArray)));
|
||||
objArray = (Object[])WrappedO.ToObject();
|
||||
objArray = (object[])WrappedO.ToObject();
|
||||
Assert.True(objArray.Length == array.Length);
|
||||
|
||||
WrappedO = NSObject.Wrap((Object)map);
|
||||
WrappedO = NSObject.Wrap((object)map);
|
||||
Assert.True(WrappedO.GetType().Equals(typeof(NSDictionary)));
|
||||
NSDictionary dict = (NSDictionary)WrappedO;
|
||||
Assert.True(((NSNumber)dict.ObjectForKey("int")).ToLong() == i);
|
||||
@@ -268,32 +262,37 @@ namespace plistcil.test
|
||||
Assert.True(((DateTime)map.get("date")).Equals(date));*/
|
||||
}
|
||||
|
||||
static bool ArrayEquals(byte[] arrayA, byte[] arrayB)
|
||||
{
|
||||
if (arrayA.Length == arrayB.Length)
|
||||
{
|
||||
for (int i = 0; i < arrayA.Length; i++)
|
||||
{
|
||||
if (arrayA[i] != arrayB[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the xml reader/writer
|
||||
*/
|
||||
[Fact]
|
||||
public static void testAsciiUtf8CharactersInQuotedString()
|
||||
public static void TestXml()
|
||||
{
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test-ascii-utf8.plist"));
|
||||
// Parse an example plist file
|
||||
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1.plist"));
|
||||
|
||||
// check the data in it
|
||||
NSDictionary d = (NSDictionary)x;
|
||||
Assert.Equal(2, d.Count);
|
||||
Assert.Equal("JÔÖú@2x.jpg", d.ObjectForKey("path").ToString());
|
||||
Assert.Equal("QÔÖú@2x 啕.jpg", d.ObjectForKey("Key QÔÖª@2x 䌡").ToString());
|
||||
}
|
||||
Assert.True(d.Count == 5);
|
||||
Assert.Equal("valueA", ((NSString)d.ObjectForKey("keyA")).ToString());
|
||||
Assert.Equal("value&B", ((NSString)d.ObjectForKey("key&B")).ToString());
|
||||
Assert.True(((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 10, 21, 30,
|
||||
DateTimeKind.Utc)) ||
|
||||
((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 9, 21, 30,
|
||||
DateTimeKind.Utc)));
|
||||
Assert.True(ArrayEquals(((NSData)d.ObjectForKey("data")).Bytes,
|
||||
new byte[] {0x00, 0x00, 0x00, 0x04, 0x10, 0x41, 0x08, 0x20, 0x82}));
|
||||
NSArray a = (NSArray)d.ObjectForKey("array");
|
||||
Assert.True(a.Count == 4);
|
||||
Assert.True(a[0].Equals(new NSNumber(true)));
|
||||
Assert.True(a[1].Equals(new NSNumber(false)));
|
||||
Assert.True(a[2].Equals(new NSNumber(87)));
|
||||
Assert.True(a[3].Equals(new NSNumber(3.14159)));
|
||||
|
||||
// read/write it, make sure we get the same thing
|
||||
PropertyListParser.SaveAsXml(x, new FileInfo("test-files/out-testXml.plist"));
|
||||
NSObject y = PropertyListParser.Parse(new FileInfo("test-files/out-testXml.plist"));
|
||||
Assert.True(x.Equals(y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
using Claunia.PropertyList;
|
||||
using System.IO;
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
using System.IO;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
public class PropertyListParserTests
|
||||
{
|
||||
static void ParseEmptyStreamTestDelegate()
|
||||
{
|
||||
using(MemoryStream stream = new MemoryStream()) PropertyListParser.Parse(stream);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void ParseEmptyStreamTest()
|
||||
{
|
||||
Assert.Throws<PropertyListFormatException>(() => ParseEmptyStreamTestDelegate());
|
||||
}
|
||||
|
||||
static void ParseEmptyStreamTestDelegate()
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
PropertyListParser.Parse(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,11 @@
|
||||
using Claunia.PropertyList;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using Claunia.PropertyList;
|
||||
using Xunit;
|
||||
|
||||
namespace plistcil.test
|
||||
{
|
||||
public class UIDTests
|
||||
{
|
||||
[Fact]
|
||||
public void ByteUidTest()
|
||||
{
|
||||
var uid = new UID((byte)0xAB);
|
||||
Assert.Equal(new byte[] { 0xAB }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SByteUidTest()
|
||||
{
|
||||
var uid = new UID("test", unchecked((sbyte)0x0F));
|
||||
Assert.Equal(new byte[] { 0x0F }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShortUidTest()
|
||||
{
|
||||
var uid = new UID("test", unchecked((short)0x0F0F));
|
||||
Assert.Equal(new byte[] { 0x0F, 0x0F }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UShortUidTest()
|
||||
{
|
||||
var uid = new UID(0xABCDu);
|
||||
Assert.Equal(new byte[] { 0xAB, 0xCD }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UIntUidTest()
|
||||
{
|
||||
var uid = new UID(0xABCDEF00u);
|
||||
Assert.Equal(new byte[] { 0xAB, 0xCD, 0xEF, 0x00 }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IntUidTest()
|
||||
{
|
||||
var uid = new UID(0xABCDEF00);
|
||||
Assert.Equal(new byte[] { 0xAB, 0xCD, 0xEF, 0x00 }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ULongUidTest()
|
||||
{
|
||||
var uid = new UID(0xABCDEF0000EFCDABu);
|
||||
Assert.Equal(new byte[] { 0xAB, 0xCD, 0xEF, 0x00, 0x00, 0xEF, 0xCD, 0xAB }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LongUidTest()
|
||||
{
|
||||
var uid = new UID(0xABCDEF0000EFCDAB);
|
||||
Assert.Equal(new byte[] { 0xAB, 0xCD, 0xEF, 0x00, 0x00, 0xEF, 0xCD, 0xAB }, uid.Bytes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[] {0xAB})]
|
||||
[InlineData(new byte[] {0xAB, 0xCD})]
|
||||
@@ -69,34 +13,90 @@ namespace plistcil.test
|
||||
[InlineData(new byte[] {0xAB, 0xCD, 0xEF, 0xFE, 0xFE, 0xEF, 0xCD, 0xAB})]
|
||||
public void UidFromArrayTest(byte[] array)
|
||||
{
|
||||
var uid = new UID(array);
|
||||
UID uid = new UID(array);
|
||||
Assert.Equal(array, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BinaryRoundTripTest()
|
||||
{
|
||||
var original = new UID(0xabcd);
|
||||
UID original = new UID(0xabcd);
|
||||
|
||||
using(MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
BinaryPropertyListWriter.Write(stream, original);
|
||||
stream.Position = 0;
|
||||
var roundtrip = BinaryPropertyListParser.Parse(stream) as UID;
|
||||
UID roundtrip = BinaryPropertyListParser.Parse(stream) as UID;
|
||||
Assert.Equal(original.Bytes, roundtrip.Bytes);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ByteUidTest()
|
||||
{
|
||||
UID uid = new UID(0xAB);
|
||||
Assert.Equal(new byte[] {0xAB}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IntUidTest()
|
||||
{
|
||||
UID uid = new UID(0xABCDEF00);
|
||||
Assert.Equal(new byte[] {0xAB, 0xCD, 0xEF, 0x00}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LongUidTest()
|
||||
{
|
||||
UID uid = new UID(0xABCDEF0000EFCDAB);
|
||||
Assert.Equal(new byte[] {0xAB, 0xCD, 0xEF, 0x00, 0x00, 0xEF, 0xCD, 0xAB}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SByteUidTest()
|
||||
{
|
||||
UID uid = new UID("test", (sbyte)0x0F);
|
||||
Assert.Equal(new byte[] {0x0F}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShortUidTest()
|
||||
{
|
||||
UID uid = new UID("test", (short)0x0F0F);
|
||||
Assert.Equal(new byte[] {0x0F, 0x0F}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UIntUidTest()
|
||||
{
|
||||
UID uid = new UID(0xABCDEF00u);
|
||||
Assert.Equal(new byte[] {0xAB, 0xCD, 0xEF, 0x00}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ULongUidTest()
|
||||
{
|
||||
UID uid = new UID(0xABCDEF0000EFCDABu);
|
||||
Assert.Equal(new byte[] {0xAB, 0xCD, 0xEF, 0x00, 0x00, 0xEF, 0xCD, 0xAB}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UShortUidTest()
|
||||
{
|
||||
UID uid = new UID(0xABCDu);
|
||||
Assert.Equal(new byte[] {0xAB, 0xCD}, uid.Bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void XmlRoundTripTest()
|
||||
{
|
||||
var original = new UID(0xabcd);
|
||||
UID original = new UID(0xabcd);
|
||||
|
||||
var plist = original.ToXmlPropertyList();
|
||||
string plist = original.ToXmlPropertyList();
|
||||
|
||||
// UIDs don't exist in XML property lists, but they are represented as strings
|
||||
// for compability purposes
|
||||
var roundtrip = XmlPropertyListParser.ParseString(plist) as NSString;
|
||||
NSString roundtrip = XmlPropertyListParser.ParseString(plist) as NSString;
|
||||
Assert.Equal("abcd", roundtrip.ToObject());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Xunit.Sdk;
|
||||
@@ -10,7 +9,7 @@ using Xunit.Sdk;
|
||||
/// <see cref="Thread.CurrentThread" /> <see cref="CultureInfo.CurrentCulture" /> and
|
||||
/// <see cref="CultureInfo.CurrentUICulture" /> with another culture.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class UseCultureAttribute : BeforeAfterTestAttribute
|
||||
{
|
||||
readonly Lazy<CultureInfo> culture;
|
||||
@@ -30,8 +29,7 @@ public class UseCultureAttribute : BeforeAfterTestAttribute
|
||||
/// <see cref="Culture" /> and <see cref="UICulture" />.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public UseCultureAttribute(string culture)
|
||||
: this(culture, culture) { }
|
||||
public UseCultureAttribute(string culture) : this(culture, culture) { }
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the culture and UI culture of the current thread with
|
||||
@@ -48,12 +46,12 @@ public class UseCultureAttribute : BeforeAfterTestAttribute
|
||||
/// <summary>
|
||||
/// Gets the culture.
|
||||
/// </summary>
|
||||
public CultureInfo Culture { get { return culture.Value; } }
|
||||
public CultureInfo Culture => culture.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UI culture.
|
||||
/// </summary>
|
||||
public CultureInfo UICulture { get { return uiCulture.Value; } }
|
||||
public CultureInfo UICulture => uiCulture.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the current <see cref="Thread.CurrentPrincipal" />
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
@@ -17,10 +15,10 @@ namespace plistcil.test
|
||||
/// A <see cref="Stream" /> which writes its output to a <see cref="Stream" /> and validates that the data which
|
||||
/// is being written to the output stream matches the data in a reference stream.
|
||||
/// </summary>
|
||||
internal class ValidatingStream : Stream
|
||||
class ValidatingStream : Stream
|
||||
{
|
||||
private Stream output;
|
||||
private Stream expectedOutput;
|
||||
Stream expectedOutput;
|
||||
Stream output;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ValidatingCompositeStream" /> class.
|
||||
@@ -38,40 +36,28 @@ namespace plistcil.test
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool CanRead => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool CanSeek => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public override bool CanWrite => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override long Length
|
||||
{
|
||||
get { return this.output.Length; }
|
||||
}
|
||||
public override long Length => output.Length;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override long Position
|
||||
{
|
||||
get { return this.output.Position; }
|
||||
set { throw new NotImplementedException(); }
|
||||
get => output.Position;
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Flush()
|
||||
{
|
||||
this.output.Flush();
|
||||
output.Flush();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -102,7 +88,7 @@ namespace plistcil.test
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
byte[] expected = new byte[buffer.Length];
|
||||
this.expectedOutput.Read(expected, offset, count);
|
||||
expectedOutput.Read(expected, offset, count);
|
||||
|
||||
byte[] bufferChunk = buffer.Skip(offset).Take(count).ToArray();
|
||||
byte[] expectedChunk = expected.Skip(offset).Take(count).ToArray();
|
||||
@@ -111,14 +97,14 @@ namespace plistcil.test
|
||||
// This will detect any errors as the invalid data is being written out - as opposed to post-
|
||||
// test binary validation.
|
||||
Assert.Equal(expectedChunk, bufferChunk);
|
||||
this.output.Write(buffer, offset, count);
|
||||
output.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
byte[] expected = new byte[buffer.Length];
|
||||
await this.expectedOutput.ReadAsync(expected, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
await expectedOutput.ReadAsync(expected, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
byte[] bufferChunk = buffer.Skip(offset).Take(count).ToArray();
|
||||
byte[] expectedChunk = expected.Skip(offset).Take(count).ToArray();
|
||||
@@ -128,7 +114,7 @@ namespace plistcil.test
|
||||
// test binary validation.
|
||||
Assert.Equal(expectedChunk, bufferChunk);
|
||||
|
||||
await this.output.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
await output.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,12 @@
|
||||
// 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;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -57,84 +57,6 @@ namespace Claunia.PropertyList
|
||||
/// @author Natalia Portillo
|
||||
public class ASCIIPropertyListParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list file.
|
||||
/// </summary>
|
||||
/// <param name="f">The ASCII property list file..</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
/// <exception cref="IOException">When an error occured while reading from the input stream.</exception>
|
||||
public static NSObject Parse(FileInfo f)
|
||||
{
|
||||
return Parse(f.OpenRead());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from an input stream.
|
||||
/// </summary>
|
||||
/// <param name="fs">The input stream that points to the property list's data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
/// <exception cref="IOException"></exception>
|
||||
public static NSObject Parse(Stream fs)
|
||||
{
|
||||
byte[] buf = PropertyListParser.ReadAll(fs);
|
||||
// Don't close the stream - that would be the responisibility of code that class
|
||||
// Parse
|
||||
return Parse(buf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a byte array.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The ASCII property list data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject Parse(byte[] bytes)
|
||||
{
|
||||
return Parse(bytes.AsSpan());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a byte array.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The ASCII property list data.</param>
|
||||
/// <param name="count">The offset at which to start reading the property list.</param>
|
||||
/// <param name="offset">The length of the property list.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject Parse(byte[] bytes, int offset, int count)
|
||||
{
|
||||
return Parse(bytes.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a byte span.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The ASCII property list data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject Parse(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
#if NATIVE_SPAN
|
||||
return ParseString(Encoding.UTF8.GetString(bytes));
|
||||
#else
|
||||
return ParseString(Encoding.UTF8.GetString(bytes.ToArray()));
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a string.
|
||||
/// </summary>
|
||||
/// <param name="value">The ASCII property list data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject ParseString(string value)
|
||||
{
|
||||
ASCIIPropertyListParser parser = new ASCIIPropertyListParser(value.ToCharArray());
|
||||
return parser.Parse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A space
|
||||
/// </summary>
|
||||
@@ -283,10 +205,7 @@ namespace Claunia.PropertyList
|
||||
/**
|
||||
* Only allow subclasses to change instantiation.
|
||||
*/
|
||||
protected ASCIIPropertyListParser()
|
||||
{
|
||||
|
||||
}
|
||||
protected ASCIIPropertyListParser() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new parser for the given property list content.
|
||||
@@ -297,6 +216,84 @@ namespace Claunia.PropertyList
|
||||
data = propertyListContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list file.
|
||||
/// </summary>
|
||||
/// <param name="f">The ASCII property list file..</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
/// <exception cref="IOException">When an error occured while reading from the input stream.</exception>
|
||||
public static NSObject Parse(FileInfo f)
|
||||
{
|
||||
return Parse(f.OpenRead());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from an input stream.
|
||||
/// </summary>
|
||||
/// <param name="fs">The input stream that points to the property list's data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
/// <exception cref="IOException"></exception>
|
||||
public static NSObject Parse(Stream fs)
|
||||
{
|
||||
byte[] buf = PropertyListParser.ReadAll(fs);
|
||||
// Don't close the stream - that would be the responisibility of code that class
|
||||
// Parse
|
||||
return Parse(buf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a byte array.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The ASCII property list data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject Parse(byte[] bytes)
|
||||
{
|
||||
return Parse(bytes.AsSpan());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a byte array.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The ASCII property list data.</param>
|
||||
/// <param name="count">The offset at which to start reading the property list.</param>
|
||||
/// <param name="offset">The length of the property list.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject Parse(byte[] bytes, int offset, int count)
|
||||
{
|
||||
return Parse(bytes.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a byte span.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The ASCII property list data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject Parse(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
#if NATIVE_SPAN
|
||||
return ParseString(Encoding.UTF8.GetString(bytes));
|
||||
#else
|
||||
return ParseString(Encoding.UTF8.GetString(bytes.ToArray()));
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an ASCII property list from a string.
|
||||
/// </summary>
|
||||
/// <param name="value">The ASCII property list data.</param>
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
|
||||
public static NSObject ParseString(string value)
|
||||
{
|
||||
ASCIIPropertyListParser parser = new ASCIIPropertyListParser(value.ToCharArray());
|
||||
return parser.Parse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the given sequence of symbols can be accepted.
|
||||
/// </summary>
|
||||
@@ -305,10 +302,9 @@ namespace Claunia.PropertyList
|
||||
bool AcceptSequence(params char[] sequence)
|
||||
{
|
||||
for(int i = 0; i < sequence.Length; i++)
|
||||
{
|
||||
if(data[index + i] != sequence[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -321,8 +317,7 @@ namespace Claunia.PropertyList
|
||||
bool Accept(params char[] acceptableSymbols)
|
||||
{
|
||||
bool symbolPresent = false;
|
||||
foreach (char c in acceptableSymbols)
|
||||
symbolPresent |= data[index] == c;
|
||||
foreach(char c in acceptableSymbols) symbolPresent |= data[index] == c;
|
||||
return symbolPresent;
|
||||
}
|
||||
|
||||
@@ -346,12 +341,11 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
if(!Accept(expectedSymbols))
|
||||
{
|
||||
String excString = "Expected '" + expectedSymbols[0] + "'";
|
||||
for (int i = 1; i < expectedSymbols.Length; i++)
|
||||
excString += " or '" + expectedSymbols[i] + "'";
|
||||
string excString = "Expected '" + expectedSymbols[0] + "'";
|
||||
for(int i = 1; i < expectedSymbols.Length; i++) excString += " or '" + expectedSymbols[i] + "'";
|
||||
|
||||
excString += " but found '" + data[index] + "'";
|
||||
throw new FormatException(String.Format("{0} at {1}", excString, index));
|
||||
throw new FormatException(string.Format("{0} at {1}", excString, index));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +357,8 @@ namespace Claunia.PropertyList
|
||||
void Expect(char expectedSymbol)
|
||||
{
|
||||
if(!Accept(expectedSymbol))
|
||||
throw new FormatException(String.Format("Expected '{0}' but found '{1}' at {2}", expectedSymbol, data[index], index));
|
||||
throw new FormatException(string.Format("Expected '{0}' but found '{1}' at {2}", expectedSymbol,
|
||||
data[index], index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -405,10 +400,7 @@ namespace Claunia.PropertyList
|
||||
commentSkipped = false;
|
||||
|
||||
//Skip whitespaces
|
||||
while (Accept(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE, WHITESPACE_SPACE, WHITESPACE_TAB))
|
||||
{
|
||||
Skip();
|
||||
}
|
||||
while(Accept(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE, WHITESPACE_SPACE, WHITESPACE_TAB)) Skip();
|
||||
|
||||
//Skip single line comments "//..."
|
||||
if(AcceptSequence(COMMENT_BEGIN_TOKEN, SINGLELINE_COMMENT_SECOND_TOKEN))
|
||||
@@ -428,12 +420,15 @@ namespace Claunia.PropertyList
|
||||
Skip(2);
|
||||
break;
|
||||
}
|
||||
|
||||
Skip();
|
||||
}
|
||||
|
||||
commentSkipped = true;
|
||||
}
|
||||
}
|
||||
while (commentSkipped); //if a comment was skipped more whitespace or another comment can follow, so skip again
|
||||
while(commentSkipped
|
||||
); //if a comment was skipped more whitespace or another comment can follow, so skip again
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -449,6 +444,7 @@ namespace Claunia.PropertyList
|
||||
s += data[index];
|
||||
Skip();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -459,12 +455,13 @@ namespace Claunia.PropertyList
|
||||
/// <param name="symbol">The symbol that can occur after the string to read.</param>
|
||||
string ReadInputUntil(char symbol)
|
||||
{
|
||||
String s = "";
|
||||
string s = "";
|
||||
while(!Accept(symbol))
|
||||
{
|
||||
s += data[index];
|
||||
Skip();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -478,17 +475,14 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
index = 0;
|
||||
//Skip Unicode byte order mark (BOM)
|
||||
if (data.Length >= 3 && (data[0] & 0xFF) == 0xEF && (data[1] & 0xFF) == 0xBB && (data[2] & 0xFF) == 0xBF)
|
||||
Skip(3);
|
||||
if(data.Length >= 3 && (data[0] & 0xFF) == 0xEF && (data[1] & 0xFF) == 0xBB &&
|
||||
(data[2] & 0xFF) == 0xBF) Skip(3);
|
||||
SkipWhitespacesAndComments();
|
||||
Expect(DICTIONARY_BEGIN_TOKEN, ARRAY_BEGIN_TOKEN, COMMENT_BEGIN_TOKEN);
|
||||
try
|
||||
{
|
||||
return ParseObject();
|
||||
}
|
||||
try { return ParseObject(); }
|
||||
catch(IndexOutOfRangeException)
|
||||
{
|
||||
throw new FormatException(String.Format("Reached end of input unexpectedly at {0}.", index));
|
||||
throw new FormatException(string.Format("Reached end of input unexpectedly at {0}.", index));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,53 +496,34 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
switch(data[index])
|
||||
{
|
||||
case ARRAY_BEGIN_TOKEN:
|
||||
{
|
||||
return ParseArray();
|
||||
}
|
||||
case DICTIONARY_BEGIN_TOKEN:
|
||||
{
|
||||
return ParseDictionary();
|
||||
}
|
||||
case DATA_BEGIN_TOKEN:
|
||||
{
|
||||
return ParseData();
|
||||
}
|
||||
case ARRAY_BEGIN_TOKEN: { return ParseArray(); }
|
||||
case DICTIONARY_BEGIN_TOKEN: { return ParseDictionary(); }
|
||||
case DATA_BEGIN_TOKEN: { return ParseData(); }
|
||||
case QUOTEDSTRING_BEGIN_TOKEN:
|
||||
{
|
||||
string quotedString = ParseQuotedString();
|
||||
//apple dates are quoted strings of length 20 and after the 4 year digits a dash is found
|
||||
if(quotedString.Length == 20 && quotedString[4] == DATE_DATE_FIELD_DELIMITER)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new NSDate(quotedString);
|
||||
}
|
||||
try { return new NSDate(quotedString); }
|
||||
catch(Exception)
|
||||
{
|
||||
//not a date? --> return string
|
||||
return new NSString(quotedString);
|
||||
}
|
||||
}
|
||||
|
||||
return new NSString(quotedString);
|
||||
}
|
||||
default:
|
||||
{
|
||||
//0-9
|
||||
if (data[index] > 0x2F && data[index] < 0x3A)
|
||||
{
|
||||
//could be a date or just a string
|
||||
return ParseDateString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(data[index] > 0x2F && data[index] < 0x3A) return ParseDateString();
|
||||
|
||||
//non-numerical -> string or boolean
|
||||
string parsedString = ParseString();
|
||||
return new NSString(parsedString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an array from the current parsing position.
|
||||
@@ -565,16 +540,12 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
objects.Add(ParseObject());
|
||||
SkipWhitespacesAndComments();
|
||||
if (Accept(ARRAY_ITEM_DELIMITER_TOKEN))
|
||||
{
|
||||
Skip();
|
||||
}
|
||||
else
|
||||
{
|
||||
break; //must have reached end of array
|
||||
}
|
||||
if(Accept(ARRAY_ITEM_DELIMITER_TOKEN)) Skip();
|
||||
else break; //must have reached end of array
|
||||
|
||||
SkipWhitespacesAndComments();
|
||||
}
|
||||
|
||||
//parse end token
|
||||
Read(ARRAY_END_TOKEN);
|
||||
return new NSArray(objects.ToArray());
|
||||
@@ -595,10 +566,8 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
//Parse key
|
||||
string keyString;
|
||||
if (Accept(QUOTEDSTRING_BEGIN_TOKEN))
|
||||
keyString = ParseQuotedString();
|
||||
else
|
||||
keyString = ParseString();
|
||||
if(Accept(QUOTEDSTRING_BEGIN_TOKEN)) keyString = ParseQuotedString();
|
||||
else keyString = ParseString();
|
||||
SkipWhitespacesAndComments();
|
||||
|
||||
//Parse assign token
|
||||
@@ -611,6 +580,7 @@ namespace Claunia.PropertyList
|
||||
Read(DICTIONARY_ITEM_DELIMITER_TOKEN);
|
||||
SkipWhitespacesAndComments();
|
||||
}
|
||||
|
||||
//skip end token
|
||||
Skip();
|
||||
return dict;
|
||||
@@ -630,16 +600,15 @@ namespace Claunia.PropertyList
|
||||
if(Accept(DATA_GSOBJECT_BEGIN_TOKEN))
|
||||
{
|
||||
Skip();
|
||||
Expect(DATA_GSBOOL_BEGIN_TOKEN, DATA_GSDATE_BEGIN_TOKEN, DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN);
|
||||
Expect(DATA_GSBOOL_BEGIN_TOKEN, DATA_GSDATE_BEGIN_TOKEN, DATA_GSINT_BEGIN_TOKEN,
|
||||
DATA_GSREAL_BEGIN_TOKEN);
|
||||
if(Accept(DATA_GSBOOL_BEGIN_TOKEN))
|
||||
{
|
||||
//Boolean
|
||||
Skip();
|
||||
Expect(DATA_GSBOOL_TRUE_TOKEN, DATA_GSBOOL_FALSE_TOKEN);
|
||||
if (Accept(DATA_GSBOOL_TRUE_TOKEN))
|
||||
obj = new NSNumber(true);
|
||||
else
|
||||
obj = new NSNumber(false);
|
||||
if(Accept(DATA_GSBOOL_TRUE_TOKEN)) obj = new NSNumber(true);
|
||||
else obj = new NSNumber(false);
|
||||
//Skip the parsed boolean token
|
||||
Skip();
|
||||
}
|
||||
@@ -657,6 +626,7 @@ namespace Claunia.PropertyList
|
||||
string numberString = ReadInputUntil(DATA_END_TOKEN);
|
||||
obj = new NSNumber(numberString);
|
||||
}
|
||||
|
||||
//parse data end token
|
||||
Read(DATA_END_TOKEN);
|
||||
}
|
||||
@@ -673,6 +643,7 @@ namespace Claunia.PropertyList
|
||||
int byteValue = Convert.ToInt32(byteString, 16);
|
||||
bytes[i] = (byte)byteValue;
|
||||
}
|
||||
|
||||
obj = new NSData(bytes);
|
||||
|
||||
//skip end token
|
||||
@@ -690,16 +661,12 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
string numericalString = ParseString();
|
||||
if(numericalString.Length > 4 && numericalString[4] == DATE_DATE_FIELD_DELIMITER)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new NSDate(numericalString);
|
||||
}
|
||||
try { return new NSDate(numericalString); }
|
||||
catch(Exception)
|
||||
{
|
||||
//An exception occurs if the string is not a date but just a string
|
||||
}
|
||||
}
|
||||
|
||||
return new NSString(numericalString);
|
||||
}
|
||||
|
||||
@@ -710,8 +677,10 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The string found at the current parsing position.</returns>
|
||||
string ParseString()
|
||||
{
|
||||
return ReadInputUntil(WHITESPACE_SPACE, WHITESPACE_TAB, WHITESPACE_NEWLINE, WHITESPACE_CARRIAGE_RETURN,
|
||||
ARRAY_ITEM_DELIMITER_TOKEN, DICTIONARY_ITEM_DELIMITER_TOKEN, DICTIONARY_ASSIGN_TOKEN, ARRAY_END_TOKEN);
|
||||
return ReadInputUntil(WHITESPACE_SPACE, WHITESPACE_TAB, WHITESPACE_NEWLINE,
|
||||
WHITESPACE_CARRIAGE_RETURN,
|
||||
ARRAY_ITEM_DELIMITER_TOKEN, DICTIONARY_ITEM_DELIMITER_TOKEN, DICTIONARY_ASSIGN_TOKEN,
|
||||
ARRAY_END_TOKEN);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -727,24 +696,22 @@ namespace Claunia.PropertyList
|
||||
string quotedString = "";
|
||||
bool unescapedBackslash = true;
|
||||
//Read from opening quotation marks to closing quotation marks and skip escaped quotation marks
|
||||
while (data[index] != QUOTEDSTRING_END_TOKEN || (data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash))
|
||||
while(data[index] != QUOTEDSTRING_END_TOKEN ||
|
||||
data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash)
|
||||
{
|
||||
quotedString += data[index];
|
||||
if(Accept(QUOTEDSTRING_ESCAPE_TOKEN))
|
||||
{
|
||||
unescapedBackslash = !(data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash);
|
||||
}
|
||||
Skip();
|
||||
}
|
||||
|
||||
string unescapedString;
|
||||
try
|
||||
{
|
||||
unescapedString = ParseQuotedString(quotedString);
|
||||
}
|
||||
try { unescapedString = ParseQuotedString(quotedString); }
|
||||
catch(Exception)
|
||||
{
|
||||
throw new FormatException(String.Format("The quoted string could not be parsed at {0}.", index));
|
||||
throw new FormatException(string.Format("The quoted string could not be parsed at {0}.", index));
|
||||
}
|
||||
|
||||
//skip end token
|
||||
Skip();
|
||||
return unescapedString;
|
||||
@@ -755,34 +722,36 @@ namespace Claunia.PropertyList
|
||||
/// Such strings can contain escape sequences which are unescaped in this method.
|
||||
/// </summary>
|
||||
/// <returns>The unescaped string in UTF-8 or ASCII format, depending on the contained characters.</returns>
|
||||
/// <param name="s">The escaped string according to the ASCII property list format, without leading and trailing quotation marks.</param>
|
||||
/// <param name="s">
|
||||
/// The escaped string according to the ASCII property list format, without leading and trailing quotation
|
||||
/// marks.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentException">If the en-/decoder for the UTF-8 or ASCII encoding could not be loaded</exception>
|
||||
/// <exception cref="EncoderFallbackException">If the string is encoded neither in ASCII nor in UTF-8</exception>
|
||||
public static string ParseQuotedString(string s)
|
||||
{
|
||||
List<byte> strBytes = new List<byte>();
|
||||
|
||||
var characters = (IEnumerable<char>)s.ToCharArray();
|
||||
var c = characters.GetEnumerator();
|
||||
IEnumerable<char> characters = s.ToCharArray();
|
||||
IEnumerator<char> c = characters.GetEnumerator();
|
||||
|
||||
while(c.MoveNext())
|
||||
{
|
||||
switch(c.Current)
|
||||
{
|
||||
case '\\':
|
||||
{ //An escaped sequence is following
|
||||
{
|
||||
//An escaped sequence is following
|
||||
byte[] bts = Encoding.UTF8.GetBytes(ParseEscapedSequence(c));
|
||||
foreach (byte b in bts)
|
||||
strBytes.Add(b);
|
||||
foreach(byte b in bts) strBytes.Add(b);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{ //a normal ASCII char
|
||||
{
|
||||
//a normal ASCII char
|
||||
strBytes.AddRange(Encoding.BigEndianUnicode.GetBytes(new[] {c.Current}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] bytArr = new byte[strBytes.Count];
|
||||
int i = 0;
|
||||
foreach(byte b in strBytes)
|
||||
@@ -790,6 +759,7 @@ namespace Claunia.PropertyList
|
||||
bytArr[i] = b;
|
||||
i++;
|
||||
}
|
||||
|
||||
//Build string
|
||||
string result = Encoding.BigEndianUnicode.GetString(bytArr);
|
||||
|
||||
@@ -797,6 +767,7 @@ namespace Claunia.PropertyList
|
||||
// --> use ASCII encoding
|
||||
if(IsASCIIEncodable(result))
|
||||
return Encoding.ASCII.GetString(Encoding.Convert(Encoding.BigEndianUnicode, Encoding.ASCII, bytArr));
|
||||
|
||||
//The string contains characters outside the ASCII codepage
|
||||
// --> use the UTF-8 encoded string
|
||||
return result;
|
||||
@@ -808,35 +779,23 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The unescaped character as a string.</returns>
|
||||
/// <param name="iterator">The string character iterator pointing to the first character after the backslash</param>
|
||||
/// <exception cref="EncoderFallbackException">If an invalid Unicode or ASCII escape sequence is found.</exception>
|
||||
private static string ParseEscapedSequence(IEnumerator<char> iterator)
|
||||
static string ParseEscapedSequence(IEnumerator<char> iterator)
|
||||
{
|
||||
iterator.MoveNext();
|
||||
char c = iterator.Current;
|
||||
if (c == '\\')
|
||||
{
|
||||
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\\' });
|
||||
}
|
||||
else if (c == '"')
|
||||
{
|
||||
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\"' });
|
||||
}
|
||||
else if (c == 'b')
|
||||
{
|
||||
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\b' });
|
||||
}
|
||||
else if (c == 'n')
|
||||
{
|
||||
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\n' });
|
||||
}
|
||||
else if (c == 'r')
|
||||
{
|
||||
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\r' });
|
||||
}
|
||||
else if (c == 't')
|
||||
{
|
||||
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\t' });
|
||||
}
|
||||
else if (c == 'U' || c == 'u')
|
||||
if(c == '\\') return Encoding.UTF8.GetString(new byte[] {0, (byte)'\\'});
|
||||
|
||||
if(c == '"') return Encoding.UTF8.GetString(new byte[] {0, (byte)'\"'});
|
||||
|
||||
if(c == 'b') return Encoding.UTF8.GetString(new byte[] {0, (byte)'\b'});
|
||||
|
||||
if(c == 'n') return Encoding.UTF8.GetString(new byte[] {0, (byte)'\n'});
|
||||
|
||||
if(c == 'r') return Encoding.UTF8.GetString(new byte[] {0, (byte)'\r'});
|
||||
|
||||
if(c == 't') return Encoding.UTF8.GetString(new byte[] {0, (byte)'\t'});
|
||||
|
||||
if(c == 'U' || c == 'u')
|
||||
{
|
||||
//4 digit hex Unicode value
|
||||
string byte1 = "";
|
||||
@@ -870,10 +829,10 @@ namespace Claunia.PropertyList
|
||||
internal static bool IsASCIIEncodable(string text)
|
||||
{
|
||||
foreach(char c in text)
|
||||
if ((int)c > 0x7F)
|
||||
if(c > 0x7F)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
// 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.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -35,7 +37,8 @@ namespace Claunia.PropertyList
|
||||
/// 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.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Parsing is done by calling the static <see cref="Parse(byte[])" />,
|
||||
/// <see cref="Parse(FileInfo)" /> and <see cref="Parse(Stream)" /> methods.
|
||||
/// </para>
|
||||
@@ -44,7 +47,7 @@ namespace Claunia.PropertyList
|
||||
/// @author Natalia Portillo
|
||||
public class BinaryPropertyListParser
|
||||
{
|
||||
private readonly static Encoding utf16BigEndian = Encoding.GetEncoding("UTF-16BE");
|
||||
static readonly Encoding utf16BigEndian = Encoding.GetEncoding("UTF-16BE");
|
||||
|
||||
/// <summary>
|
||||
/// Major version of the property list format
|
||||
@@ -71,9 +74,7 @@ namespace Claunia.PropertyList
|
||||
/// static parse methods.
|
||||
/// </summary>
|
||||
/// <see cref="Parse(byte[])" />
|
||||
protected BinaryPropertyListParser()
|
||||
{
|
||||
}
|
||||
protected BinaryPropertyListParser() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parses a binary property list from a byte array.
|
||||
@@ -117,18 +118,14 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
/// <param name="bytes">The binary property list's data.</param>
|
||||
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
|
||||
private NSObject DoParse(ReadOnlySpan<byte> bytes)
|
||||
NSObject DoParse(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if(bytes.Length < 8
|
||||
|| bytes[0] != 'b'
|
||||
|| bytes[1] != 'p'
|
||||
|| bytes[2] != 'l'
|
||||
|| bytes[3] != 'i'
|
||||
|| bytes[4] != 's'
|
||||
|| bytes[5] != 't')
|
||||
if(bytes.Length < 8 || bytes[0] != 'b' || bytes[1] != 'p' || bytes[2] != 'l' || bytes[3] != 'i' ||
|
||||
bytes[4] != 's' || bytes[5] != 't')
|
||||
{
|
||||
var magic = Encoding.ASCII.GetString(bytes.Slice(0, 8).ToArray());
|
||||
throw new PropertyListFormatException("The given data is no binary property list. Wrong magic bytes: " + magic);
|
||||
string magic = Encoding.ASCII.GetString(bytes.Slice(0, 8).ToArray());
|
||||
throw new PropertyListFormatException("The given data is no binary property list. Wrong magic bytes: " +
|
||||
magic);
|
||||
}
|
||||
|
||||
majorVersion = bytes[6] - 0x30; //ASCII number
|
||||
@@ -141,16 +138,15 @@ namespace Claunia.PropertyList
|
||||
// 2.0 - Snow Lion
|
||||
|
||||
if(majorVersion > 0)
|
||||
{
|
||||
// Version 1.0+ is not even supported by OS X's own parser
|
||||
throw new PropertyListFormatException("Unsupported binary property list format: v" + majorVersion + "." + minorVersion + ". " +
|
||||
throw new PropertyListFormatException("Unsupported binary property list format: v" + majorVersion +
|
||||
"." + minorVersion +
|
||||
". " +
|
||||
"Version 1.0 and later are not yet supported.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle trailer, last 32 bytes of the file
|
||||
*/
|
||||
var trailer = bytes.Slice(bytes.Length - 32, 32);
|
||||
ReadOnlySpan<byte> trailer = bytes.Slice(bytes.Length - 32, 32);
|
||||
//6 null bytes (index 0 to 5)
|
||||
int offsetSize = trailer[6];
|
||||
objectRefSize = trailer[7];
|
||||
@@ -165,7 +161,7 @@ namespace Claunia.PropertyList
|
||||
|
||||
for(int i = 0; i < numObjects; i++)
|
||||
{
|
||||
var offsetBytes = bytes.Slice(offsetTableOffset + i * offsetSize, offsetSize);
|
||||
ReadOnlySpan<byte> offsetBytes = bytes.Slice(offsetTableOffset + i * offsetSize, offsetSize);
|
||||
offsetTable[i] = (int)ParseUnsignedInt(offsetBytes);
|
||||
}
|
||||
|
||||
@@ -202,7 +198,9 @@ namespace Claunia.PropertyList
|
||||
/// 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-855.17/CFBinaryPList.c">
|
||||
/// Apple's binary property list parser implementation</a>.
|
||||
/// Apple's binary property list parser implementation
|
||||
/// </a>
|
||||
/// .
|
||||
/// </summary>
|
||||
/// <returns>The parsed object.</returns>
|
||||
/// <param name="obj">The object ID.</param>
|
||||
@@ -212,7 +210,7 @@ namespace Claunia.PropertyList
|
||||
int offset = offsetTable[obj];
|
||||
byte type = bytes[offset];
|
||||
int objType = (type & 0xF0) >> 4; //First 4 bits
|
||||
int objInfo = (type & 0x0F); //Second 4 bits
|
||||
int objInfo = type & 0x0F; //Second 4 bits
|
||||
switch(objType)
|
||||
{
|
||||
case 0x0:
|
||||
@@ -259,6 +257,7 @@ namespace Claunia.PropertyList
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x1:
|
||||
@@ -277,9 +276,11 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
//Date
|
||||
if(objInfo != 0x3)
|
||||
{
|
||||
throw new PropertyListFormatException("The given binary property list contains a date object of an unknown type (" + objInfo + ")");
|
||||
}
|
||||
throw new
|
||||
PropertyListFormatException("The given binary property list contains a date object of an unknown type (" +
|
||||
objInfo +
|
||||
")");
|
||||
|
||||
return new NSDate(bytes.Slice(offset + 1, 8));
|
||||
}
|
||||
case 0x4:
|
||||
@@ -328,11 +329,12 @@ namespace Claunia.PropertyList
|
||||
NSArray array = new NSArray(length);
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
int objRef = (int)ParseUnsignedInt(bytes.Slice(offset + arrayOffset + i * objectRefSize, objectRefSize));
|
||||
int objRef =
|
||||
(int)ParseUnsignedInt(bytes.Slice(offset + arrayOffset + i * objectRefSize, objectRefSize));
|
||||
array.Add(ParseObject(bytes, objRef));
|
||||
}
|
||||
return array;
|
||||
|
||||
return array;
|
||||
}
|
||||
case 0xB:
|
||||
{
|
||||
@@ -342,9 +344,12 @@ namespace Claunia.PropertyList
|
||||
NSSet set = new NSSet(true);
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
int objRef = (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, objectRefSize));
|
||||
int objRef =
|
||||
(int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize,
|
||||
objectRefSize));
|
||||
set.AddObject(ParseObject(bytes, objRef));
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
case 0xC:
|
||||
@@ -355,9 +360,12 @@ namespace Claunia.PropertyList
|
||||
NSSet set = new NSSet();
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
int objRef = (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, objectRefSize));
|
||||
int objRef =
|
||||
(int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize,
|
||||
objectRefSize));
|
||||
set.AddObject(ParseObject(bytes, objRef));
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
case 0xD:
|
||||
@@ -369,20 +377,29 @@ namespace Claunia.PropertyList
|
||||
NSDictionary dict = new NSDictionary(length);
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
int keyRef = (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, objectRefSize));
|
||||
int valRef = (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + (length * objectRefSize) + i * objectRefSize, objectRefSize));
|
||||
int keyRef =
|
||||
(int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize,
|
||||
objectRefSize));
|
||||
int valRef =
|
||||
(int)
|
||||
ParseUnsignedInt(bytes.Slice(offset + contentOffset + length * objectRefSize + i * objectRefSize,
|
||||
objectRefSize));
|
||||
NSObject key = ParseObject(bytes, keyRef);
|
||||
NSObject val = ParseObject(bytes, valRef);
|
||||
dict.Add(key.ToString(), val);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.WriteLine("WARNING: The given binary property list contains an object of unknown type (" + objType + ")");
|
||||
Debug.WriteLine("WARNING: The given binary property list contains an object of unknown type (" +
|
||||
objType +
|
||||
")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -392,7 +409,8 @@ namespace Claunia.PropertyList
|
||||
/// <returns>An array with the length two. First entry is the length, second entry the offset at which the content starts.</returns>
|
||||
/// <param name="objInfo">Object information byte.</param>
|
||||
/// <param name="offset">Offset in the byte array at which the object is located.</param>
|
||||
void ReadLengthAndOffset(ReadOnlySpan<byte> bytes, int objInfo, int offset, out int lengthValue, out int offsetValue)
|
||||
void ReadLengthAndOffset(ReadOnlySpan<byte> bytes, int objInfo, int offset, out int lengthValue,
|
||||
out int offsetValue)
|
||||
{
|
||||
lengthValue = objInfo;
|
||||
offsetValue = 1;
|
||||
@@ -401,16 +419,12 @@ namespace Claunia.PropertyList
|
||||
int int_type = bytes[offset + 1];
|
||||
int intType = (int_type & 0xF0) >> 4;
|
||||
if(intType != 0x1)
|
||||
{
|
||||
Debug.WriteLine("BinaryPropertyListParser: Length integer has an unexpected type" + intType + ". Attempting to parse anyway...");
|
||||
}
|
||||
Debug.WriteLine("BinaryPropertyListParser: Length integer has an unexpected type" + intType +
|
||||
". Attempting to parse anyway...");
|
||||
int intInfo = int_type & 0x0F;
|
||||
int intLength = (int)Math.Pow(2, intInfo);
|
||||
offsetValue = 2 + intLength;
|
||||
if (intLength < 3)
|
||||
{
|
||||
lengthValue = (int)ParseUnsignedInt(bytes.Slice(offset + 2, intLength));
|
||||
}
|
||||
if(intLength < 3) lengthValue = (int)ParseUnsignedInt(bytes.Slice(offset + 2, intLength));
|
||||
else
|
||||
{
|
||||
// BigInteger is Little-Endian in .NET, swap the thing.
|
||||
@@ -419,7 +433,7 @@ namespace Claunia.PropertyList
|
||||
Array.Reverse(bigEBigInteger);
|
||||
bigEBigInteger[bigEBigInteger.Length - 1] = 0x00; // Be sure to get unsigned BigInteger
|
||||
|
||||
lengthValue = (int)new System.Numerics.BigInteger(bigEBigInteger);
|
||||
lengthValue = (int)new BigInteger(bigEBigInteger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,51 +451,33 @@ namespace Claunia.PropertyList
|
||||
for(int i = 0; i < numCharacters; i++)
|
||||
{
|
||||
int tempOffset = offset + length;
|
||||
if (bytes.Length <= tempOffset)
|
||||
if(bytes.Length <= tempOffset) return numCharacters;
|
||||
|
||||
if(bytes[tempOffset] < 0x80) length++;
|
||||
if(bytes[tempOffset] < 0xC2) return numCharacters;
|
||||
|
||||
if(bytes[tempOffset] < 0xE0)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
if((bytes[tempOffset + 1] & 0xC0) != 0x80) 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
|
||||
if((bytes[tempOffset + 1] & 0xC0) != 0x80 || (bytes[tempOffset + 2] & 0xC0) != 0x80)
|
||||
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;
|
||||
}
|
||||
if((bytes[tempOffset + 1] & 0xC0) != 0x80 || (bytes[tempOffset + 2] & 0xC0) != 0x80 ||
|
||||
(bytes[tempOffset + 3] & 0xC0) != 0x80) return numCharacters;
|
||||
|
||||
length += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
@@ -492,15 +488,10 @@ namespace Claunia.PropertyList
|
||||
/// <param name="bytes">The unsigned integer represented by the given bytes.</param>
|
||||
public static long ParseUnsignedInt(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (bytes.Length <= 4)
|
||||
{
|
||||
return ParseLong(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(bytes.Length <= 4) return ParseLong(bytes);
|
||||
|
||||
return ParseLong(bytes) & 0xFFFFFFFFL;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an unsigned integers from a byte array.
|
||||
@@ -521,23 +512,19 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
switch(bytes.Length)
|
||||
{
|
||||
case 1:
|
||||
return bytes[0];
|
||||
case 1: return bytes[0];
|
||||
|
||||
case 2:
|
||||
return BinaryPrimitives.ReadUInt16BigEndian(bytes);
|
||||
case 2: return BinaryPrimitives.ReadUInt16BigEndian(bytes);
|
||||
|
||||
case 3:
|
||||
throw new NotSupportedException();
|
||||
case 3: throw new NotSupportedException();
|
||||
|
||||
case 4:
|
||||
return BinaryPrimitives.ReadUInt32BigEndian(bytes);
|
||||
case 4: return BinaryPrimitives.ReadUInt32BigEndian(bytes);
|
||||
|
||||
case 8:
|
||||
return (long)BinaryPrimitives.ReadUInt64BigEndian(bytes);
|
||||
case 8: return (long)BinaryPrimitives.ReadUInt64BigEndian(bytes);
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), $"Cannot read a byte span of length {bytes.Length}");
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes),
|
||||
$"Cannot read a byte span of length {bytes.Length}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,10 +535,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="bytes">The bytes representing the double.</param>
|
||||
public static double ParseDouble(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (bytes.Length == 8)
|
||||
return BitConverter.Int64BitsToDouble(ParseLong(bytes));
|
||||
if (bytes.Length == 4)
|
||||
return BitConverter.ToSingle(BitConverter.GetBytes(ParseLong(bytes)), 0);
|
||||
if(bytes.Length == 8) return BitConverter.Int64BitsToDouble(ParseLong(bytes));
|
||||
if(bytes.Length == 4) return BitConverter.ToSingle(BitConverter.GetBytes(ParseLong(bytes)), 0);
|
||||
|
||||
throw new ArgumentException("bad byte array length " + bytes.Length);
|
||||
}
|
||||
|
||||
@@ -566,12 +552,10 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
int length = endIndex - startIndex;
|
||||
if(length < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("startIndex (" + startIndex + ")" + " > endIndex (" + endIndex + ")");
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("startIndex (" + startIndex + ")" + " > endIndex (" + endIndex +
|
||||
")");
|
||||
|
||||
return src.Slice(startIndex, endIndex - startIndex).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,46 +6,33 @@ namespace Claunia.PropertyList
|
||||
public partial class BinaryPropertyListWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// The equality comparer which is used when adding an object to the <see cref="BinaryPropertyListWriter.idMap" />. In most cases,
|
||||
/// The equality comparer which is used when adding an object to the <see cref="BinaryPropertyListWriter.idMap" />. In
|
||||
/// most cases,
|
||||
/// objects are always added. The only exception are very specific strings, which are only added once.
|
||||
/// </summary>
|
||||
private class AddObjectEqualityComparer : EqualityComparer<NSObject>
|
||||
class AddObjectEqualityComparer : EqualityComparer<NSObject>
|
||||
{
|
||||
public override bool Equals(NSObject x, NSObject y)
|
||||
{
|
||||
var a = x as NSString;
|
||||
var b = y as NSString;
|
||||
NSString a = x as NSString;
|
||||
NSString b = y as NSString;
|
||||
|
||||
if (a == null || b == null)
|
||||
{
|
||||
return object.ReferenceEquals(x, y);
|
||||
}
|
||||
if(a == null || b == null) return ReferenceEquals(x, y);
|
||||
|
||||
if (!BinaryPropertyListWriter.IsSerializationPrimitive(a) || !BinaryPropertyListWriter.IsSerializationPrimitive(b))
|
||||
{
|
||||
return object.ReferenceEquals(x, y);
|
||||
}
|
||||
if(!IsSerializationPrimitive(a) || !IsSerializationPrimitive(b)) return ReferenceEquals(x, y);
|
||||
|
||||
return string.Equals(a.Content, b.Content, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override int GetHashCode(NSObject obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(obj == null) return 0;
|
||||
|
||||
NSString s = obj as NSString;
|
||||
if(s != null && IsSerializationPrimitive(s)) return s.Content.GetHashCode();
|
||||
|
||||
var s = obj as NSString;
|
||||
if (s != null && BinaryPropertyListWriter.IsSerializationPrimitive(s))
|
||||
{
|
||||
return s.Content.GetHashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -10,10 +9,11 @@ namespace Claunia.PropertyList
|
||||
/// The logic is slightly different from <see cref="AddObjectEqualityComparer" />, results in two equivalent objects
|
||||
/// (UIDs mainly) being added to the <see cref="BinaryPropertyListWriter.idMap" />. Whenever the ID for one of
|
||||
/// those equivalent objects is requested, the first ID is always returned.
|
||||
/// This means that there are "orphan" objects in binary property lists - duplicate objects which are never referenced -;
|
||||
/// This means that there are "orphan" objects in binary property lists - duplicate objects which are never referenced
|
||||
/// -;
|
||||
/// this logic exists purely to maintain binary compatibility with Apple's format.
|
||||
/// </summary>
|
||||
private class GetObjectEqualityComparer : EqualityComparer<NSObject>
|
||||
class GetObjectEqualityComparer : EqualityComparer<NSObject>
|
||||
{
|
||||
public override bool Equals(NSObject x, NSObject y)
|
||||
{
|
||||
@@ -21,48 +21,26 @@ namespace Claunia.PropertyList
|
||||
// value, do not consider them equal unless they are the same instance of NSString.
|
||||
// The exceptions are UIDs, where we always compare by value, and "primitive" strings (a list of well-known
|
||||
// strings), which are treaded specially and "recycled".
|
||||
if (x is UID)
|
||||
{
|
||||
return x.Equals(y);
|
||||
}
|
||||
else if (x is NSNumber && BinaryPropertyListWriter.IsSerializationPrimitive((NSNumber)x))
|
||||
{
|
||||
return x.Equals(y);
|
||||
}
|
||||
else if (x is NSString && BinaryPropertyListWriter.IsSerializationPrimitive((NSString)x))
|
||||
{
|
||||
return x.Equals(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return object.ReferenceEquals(x, y);
|
||||
}
|
||||
if(x is UID) return x.Equals(y);
|
||||
|
||||
if(x is NSNumber && IsSerializationPrimitive((NSNumber)x)) return x.Equals(y);
|
||||
if(x is NSString && IsSerializationPrimitive((NSString)x)) return x.Equals(y);
|
||||
|
||||
return ReferenceEquals(x, y);
|
||||
}
|
||||
|
||||
public override int GetHashCode(NSObject obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(obj == null) return 0;
|
||||
|
||||
var u = obj as UID;
|
||||
if (u != null)
|
||||
{
|
||||
return u.GetHashCode();
|
||||
}
|
||||
UID u = obj as UID;
|
||||
if(u != null) return u.GetHashCode();
|
||||
|
||||
var n = obj as NSNumber;
|
||||
if (n != null && BinaryPropertyListWriter.IsSerializationPrimitive(n))
|
||||
{
|
||||
return n.ToObject().GetHashCode();
|
||||
}
|
||||
NSNumber n = obj as NSNumber;
|
||||
if(n != null && IsSerializationPrimitive(n)) return n.ToObject().GetHashCode();
|
||||
|
||||
var s = obj as NSString;
|
||||
if (s != null && BinaryPropertyListWriter.IsSerializationPrimitive(s))
|
||||
{
|
||||
return s.Content.GetHashCode();
|
||||
}
|
||||
NSString s = obj as NSString;
|
||||
if(s != null && IsSerializationPrimitive(s)) return s.Content.GetHashCode();
|
||||
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
|
||||
@@ -22,11 +22,10 @@
|
||||
// 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.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -34,7 +33,8 @@ namespace Claunia.PropertyList
|
||||
/// <para>
|
||||
/// A BinaryPropertyListWriter is a helper class for writing out
|
||||
/// binary property list files.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 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.
|
||||
@@ -61,20 +61,50 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
public const int VERSION_20 = 20;
|
||||
|
||||
// map from object to its ID
|
||||
readonly Dictionary<NSObject, int> idDict = new Dictionary<NSObject, int>(new AddObjectEqualityComparer());
|
||||
readonly Dictionary<NSObject, int> idDict2 = new Dictionary<NSObject, int>(new GetObjectEqualityComparer());
|
||||
|
||||
// # of bytes written so far
|
||||
long count;
|
||||
int currentId;
|
||||
int idSizeInBytes;
|
||||
|
||||
// raw output stream to result file
|
||||
Stream outStream;
|
||||
|
||||
int version = VERSION_00;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether two equivalent objects should be serialized once in the binary property list file, or whether
|
||||
/// the value should be stored multiple times in the binary property list file. The default is <see langword="false"/>.
|
||||
/// Creates a new binary property list writer
|
||||
/// </summary>
|
||||
/// <param name="outStr">The output stream into which the binary property list will be written</param>
|
||||
/// <exception cref="IOException">If an error occured while writing to the stream</exception>
|
||||
public BinaryPropertyListWriter(Stream outStr)
|
||||
{
|
||||
outStream = outStr;
|
||||
}
|
||||
|
||||
public BinaryPropertyListWriter(Stream outStr, int version)
|
||||
{
|
||||
this.version = version;
|
||||
outStream = outStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether two equivalent objects should be serialized once in the binary property
|
||||
/// list file, or whether
|
||||
/// the value should be stored multiple times in the binary property list file. The default is <see langword="false" />
|
||||
/// .
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In most scenarios, you want this to be <see langword="true"/>, as it reduces the size of the binary proeprty list file. However,
|
||||
/// by default, the Apple tools do not seem to implement this optimization, so set this value to <see langword="false"/> if you
|
||||
/// In most scenarios, you want this to be <see langword="true" />, as it reduces the size of the binary proeprty list
|
||||
/// file. However,
|
||||
/// by default, the Apple tools do not seem to implement this optimization, so set this value to
|
||||
/// <see langword="false" /> if you
|
||||
/// want to maintain binary compatibility with the Apple tools.
|
||||
/// </remarks>
|
||||
public bool ReuseObjectIds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public bool ReuseObjectIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Finds out the minimum binary property list format version that
|
||||
@@ -85,18 +115,14 @@ namespace Claunia.PropertyList
|
||||
static int GetMinimumRequiredVersion(NSObject root)
|
||||
{
|
||||
int minVersion = VERSION_00;
|
||||
if (root == null)
|
||||
{
|
||||
minVersion = VERSION_10;
|
||||
}
|
||||
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;
|
||||
if(v > minVersion) minVersion = v;
|
||||
}
|
||||
}
|
||||
else if(root is NSArray)
|
||||
@@ -105,8 +131,7 @@ namespace Claunia.PropertyList
|
||||
foreach(NSObject o in array)
|
||||
{
|
||||
int v = GetMinimumRequiredVersion(o);
|
||||
if (v > minVersion)
|
||||
minVersion = v;
|
||||
if(v > minVersion) minVersion = v;
|
||||
}
|
||||
}
|
||||
else if(root is NSSet)
|
||||
@@ -117,10 +142,10 @@ namespace Claunia.PropertyList
|
||||
foreach(NSObject o in set.AllObjects())
|
||||
{
|
||||
int v = GetMinimumRequiredVersion(o);
|
||||
if (v > minVersion)
|
||||
minVersion = v;
|
||||
if(v > minVersion) minVersion = v;
|
||||
}
|
||||
}
|
||||
|
||||
return minVersion;
|
||||
}
|
||||
|
||||
@@ -132,10 +157,7 @@ namespace Claunia.PropertyList
|
||||
/// <exception cref="IOException"></exception>
|
||||
public static void Write(FileInfo file, NSObject root)
|
||||
{
|
||||
using (FileStream fous = file.OpenWrite())
|
||||
{
|
||||
Write(fous, root);
|
||||
}
|
||||
using(FileStream fous = file.OpenWrite()) Write(fous, root);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -149,10 +171,16 @@ namespace Claunia.PropertyList
|
||||
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")));
|
||||
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.");
|
||||
"The required version of the binary format (" + versionString +
|
||||
") is not yet supported.");
|
||||
}
|
||||
|
||||
BinaryPropertyListWriter w = new BinaryPropertyListWriter(outStream, minVersion);
|
||||
w.Write(root);
|
||||
}
|
||||
@@ -171,36 +199,6 @@ namespace Claunia.PropertyList
|
||||
return bout.ToArray();
|
||||
}
|
||||
|
||||
int version = VERSION_00;
|
||||
|
||||
// raw output stream to result file
|
||||
Stream outStream;
|
||||
|
||||
// # of bytes written so far
|
||||
long count;
|
||||
|
||||
// map from object to its ID
|
||||
readonly Dictionary<NSObject, int> idDict = new Dictionary<NSObject, int>(new AddObjectEqualityComparer());
|
||||
readonly Dictionary<NSObject, int> idDict2 = new Dictionary<NSObject, int>(new GetObjectEqualityComparer());
|
||||
int currentId = 0;
|
||||
int idSizeInBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new binary property list writer
|
||||
/// </summary>
|
||||
/// <param name="outStr">The output stream into which the binary property list will be written</param>
|
||||
/// <exception cref="IOException">If an error occured while writing to the stream</exception>
|
||||
public BinaryPropertyListWriter(Stream outStr)
|
||||
{
|
||||
outStream = outStr;
|
||||
}
|
||||
|
||||
public BinaryPropertyListWriter(Stream outStr, int version)
|
||||
{
|
||||
this.version = version;
|
||||
outStream = outStr;
|
||||
}
|
||||
|
||||
public void Write(NSObject root)
|
||||
{
|
||||
// magic bytes
|
||||
@@ -240,28 +238,19 @@ namespace Claunia.PropertyList
|
||||
long[] offsets = new long[idDict.Count];
|
||||
|
||||
// write each object, save offset
|
||||
foreach (var pair in idDict)
|
||||
foreach(KeyValuePair<NSObject, int> pair in idDict)
|
||||
{
|
||||
NSObject obj = pair.Key;
|
||||
int id = pair.Value;
|
||||
offsets[id] = count;
|
||||
if (obj == null)
|
||||
{
|
||||
Write(0x00);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.ToBinary(this);
|
||||
}
|
||||
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);
|
||||
}
|
||||
foreach(long offset in offsets) WriteBytes(offset, offsetSizeInBytes);
|
||||
|
||||
if(version != VERSION_15)
|
||||
{
|
||||
@@ -286,63 +275,44 @@ namespace Claunia.PropertyList
|
||||
|
||||
internal void AssignID(NSObject obj)
|
||||
{
|
||||
if (this.ReuseObjectIds)
|
||||
if(ReuseObjectIds)
|
||||
{
|
||||
if (!this.idDict.ContainsKey(obj))
|
||||
{
|
||||
idDict.Add(obj, currentId++);
|
||||
}
|
||||
if(!idDict.ContainsKey(obj)) idDict.Add(obj, currentId++);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.idDict2.ContainsKey(obj))
|
||||
{
|
||||
idDict2.Add(obj, currentId);
|
||||
}
|
||||
if (!this.idDict.ContainsKey(obj))
|
||||
{
|
||||
idDict.Add(obj, currentId++);
|
||||
}
|
||||
if(!idDict2.ContainsKey(obj)) idDict2.Add(obj, currentId);
|
||||
if(!idDict.ContainsKey(obj)) idDict.Add(obj, currentId++);
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetID(NSObject obj)
|
||||
{
|
||||
if (this.ReuseObjectIds)
|
||||
{
|
||||
return idDict[obj];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ReuseObjectIds) return idDict[obj];
|
||||
|
||||
return idDict2[obj];
|
||||
}
|
||||
}
|
||||
|
||||
static int ComputeIdSizeInBytes(int numberOfIds)
|
||||
{
|
||||
if (numberOfIds < 256)
|
||||
return 1;
|
||||
if(numberOfIds < 256) return 1;
|
||||
|
||||
return numberOfIds < 65536 ? 2 : 4;
|
||||
}
|
||||
|
||||
static int ComputeOffsetSizeInBytes(long maxOffset)
|
||||
{
|
||||
if (maxOffset < 256)
|
||||
return 1;
|
||||
if (maxOffset < 65536)
|
||||
return 2;
|
||||
if(maxOffset < 256) return 1;
|
||||
if(maxOffset < 65536) return 2;
|
||||
|
||||
return maxOffset < 4294967296L ? 4 : 8;
|
||||
}
|
||||
|
||||
internal void WriteIntHeader(int kind, int value)
|
||||
{
|
||||
if (value < 0)
|
||||
throw new ArgumentException("value must be greater than or equal to 0", "value");
|
||||
if(value < 0) throw new ArgumentException("value must be greater than or equal to 0", "value");
|
||||
|
||||
if (value < 15)
|
||||
{
|
||||
Write((kind << 4) + value);
|
||||
}
|
||||
if(value < 15) Write((kind << 4) + value);
|
||||
else if(value < 256)
|
||||
{
|
||||
Write((kind << 4) + 15);
|
||||
@@ -383,17 +353,14 @@ namespace Claunia.PropertyList
|
||||
outStream.Write(bytes);
|
||||
count += bytes.Length;
|
||||
#else
|
||||
this.Write(bytes.ToArray());
|
||||
Write(bytes.ToArray());
|
||||
#endif
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
for(int i = bytes - 1; i >= 0; i--) Write((int)(value >> (8 * i)));
|
||||
}
|
||||
|
||||
internal void WriteID(int id)
|
||||
@@ -413,27 +380,17 @@ namespace Claunia.PropertyList
|
||||
|
||||
internal static bool IsSerializationPrimitive(NSString obj)
|
||||
{
|
||||
var content = obj.Content;
|
||||
string content = obj.Content;
|
||||
|
||||
// This is a list of "special" values which are only added once to a binary property
|
||||
// list, and can be referenced multiple times.
|
||||
return content == "$class"
|
||||
|| content == "$classes"
|
||||
|| content == "$classname"
|
||||
|| content == "NS.objects"
|
||||
|| content == "NS.keys"
|
||||
|| content == "NS.base"
|
||||
|| content == "NS.relative"
|
||||
|| content == "NS.string"
|
||||
|| content == "NSURL"
|
||||
|| content == "NSDictionary"
|
||||
|| content == "NSObject"
|
||||
|| content == "NSMutableDictionary"
|
||||
|| content == "NSMutableArray"
|
||||
|| content == "NSArray"
|
||||
|| content == "NSUUID"
|
||||
|| content == "NSKeyedArchiver"
|
||||
|| content == "NSMutableString";
|
||||
return content == "$class" || content == "$classes" || content == "$classname" ||
|
||||
content == "NS.objects" ||
|
||||
content == "NS.keys" || content == "NS.base" || content == "NS.relative" ||
|
||||
content == "NS.string" ||
|
||||
content == "NSURL" || content == "NSDictionary" || content == "NSObject" ||
|
||||
content == "NSMutableDictionary" || content == "NSMutableArray" || content == "NSArray" ||
|
||||
content == "NSUUID" || content == "NSKeyedArchiver" || content == "NSMutableString";
|
||||
}
|
||||
|
||||
internal static bool IsSerializationPrimitive(NSNumber n)
|
||||
@@ -442,4 +399,3 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
// 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -30,52 +29,30 @@ namespace Claunia.PropertyList
|
||||
/// <inheritdoc />
|
||||
public NSObject this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.array[index];
|
||||
}
|
||||
get => array[index];
|
||||
|
||||
set
|
||||
{
|
||||
this.array[index] = value;
|
||||
}
|
||||
set => array[index] = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(object item)
|
||||
{
|
||||
this.Add(NSObject.Wrap(item));
|
||||
}
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(NSObject item)
|
||||
{
|
||||
this.array.Add(item);
|
||||
array.Add(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
this.array.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(object item)
|
||||
{
|
||||
return this.Contains(NSObject.Wrap(item));
|
||||
array.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(NSObject item)
|
||||
{
|
||||
return this.array.Contains(item);
|
||||
return array.Contains(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -87,52 +64,62 @@ namespace Claunia.PropertyList
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<NSObject> GetEnumerator()
|
||||
{
|
||||
return this.array.GetEnumerator();
|
||||
}
|
||||
|
||||
public int IndexOf(object item)
|
||||
{
|
||||
return this.array.IndexOf(NSObject.Wrap(item));
|
||||
return array.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int IndexOf(NSObject item)
|
||||
{
|
||||
return this.array.IndexOf(item);
|
||||
}
|
||||
|
||||
public void Insert(int index, object item)
|
||||
{
|
||||
this.Insert(index, NSObject.Wrap(item));
|
||||
return array.IndexOf(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Insert(int index, NSObject item)
|
||||
{
|
||||
this.array.Insert(index, item);
|
||||
}
|
||||
|
||||
public bool Remove(object item)
|
||||
{
|
||||
return this.Remove(NSObject.Wrap(item));
|
||||
array.Insert(index, item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(NSObject item)
|
||||
{
|
||||
return this.array.Remove(item);
|
||||
return array.Remove(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
this.array.RemoveAt(index);
|
||||
array.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.array.GetEnumerator();
|
||||
return array.GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(object item)
|
||||
{
|
||||
Add(Wrap(item));
|
||||
}
|
||||
|
||||
public bool Contains(object item)
|
||||
{
|
||||
return Contains(Wrap(item));
|
||||
}
|
||||
|
||||
public int IndexOf(object item)
|
||||
{
|
||||
return array.IndexOf(Wrap(item));
|
||||
}
|
||||
|
||||
public void Insert(int index, object item)
|
||||
{
|
||||
Insert(index, Wrap(item));
|
||||
}
|
||||
|
||||
public bool Remove(object item)
|
||||
{
|
||||
return Remove(Wrap(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,9 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
@@ -56,6 +56,12 @@ namespace Claunia.PropertyList
|
||||
array = new List<NSObject>(a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of the array.
|
||||
/// </summary>
|
||||
/// <value>The number of elements that this array can store.</value>
|
||||
public int Count => array.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the object stored at the given index.
|
||||
/// </summary>
|
||||
@@ -75,7 +81,7 @@ namespace Claunia.PropertyList
|
||||
[Obsolete]
|
||||
public void Remove(int i)
|
||||
{
|
||||
this.array.RemoveAt(i);
|
||||
array.RemoveAt(i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -85,11 +91,11 @@ namespace Claunia.PropertyList
|
||||
/// <param name="key">The index where to store the object.</param>
|
||||
/// <param name="value">The object.</param>
|
||||
[Obsolete]
|
||||
public void SetValue(int key, Object value)
|
||||
public void SetValue(int key, object value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value", "Cannot add null values to an NSArray!");
|
||||
array[key] = NSObject.Wrap(value);
|
||||
if(value == null) throw new ArgumentNullException("value", "Cannot add null values to an NSArray!");
|
||||
|
||||
array[key] = Wrap(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -103,18 +109,6 @@ namespace Claunia.PropertyList
|
||||
return array.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of the array.
|
||||
/// </summary>
|
||||
/// <value>The number of elements that this array can store.</value>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return array.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an object is present in the array or whether it is equal
|
||||
/// to any of the objects in the array.
|
||||
@@ -122,16 +116,13 @@ namespace Claunia.PropertyList
|
||||
/// <returns><c>true</c>, when the object could be found. <c>false</c> otherwise.</returns>
|
||||
/// <param name="obj">The object to look for.</param>
|
||||
[Obsolete]
|
||||
public bool ContainsObject(Object obj)
|
||||
public bool ContainsObject(object obj)
|
||||
{
|
||||
NSObject nso = NSObject.Wrap(obj);
|
||||
NSObject nso = Wrap(obj);
|
||||
foreach(NSObject elem in array)
|
||||
{
|
||||
if(elem.Equals(nso))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -143,16 +134,13 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The index of the object, if it was found. -1 otherwise.</returns>
|
||||
/// <param name="obj">The object to look for.</param>
|
||||
[Obsolete]
|
||||
public int IndexOfObject(Object obj)
|
||||
public int IndexOfObject(object obj)
|
||||
{
|
||||
NSObject nso = NSObject.Wrap(obj);
|
||||
NSObject nso = Wrap(obj);
|
||||
for(int i = 0; i < array.Count; i++)
|
||||
{
|
||||
if(array[i].Equals(nso))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -165,16 +153,13 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The index of the object, if it was found. -1 otherwise.</returns>
|
||||
/// <param name="obj">The object to look for.</param>
|
||||
[Obsolete]
|
||||
public int IndexOfIdenticalObject(Object obj)
|
||||
public int IndexOfIdenticalObject(object obj)
|
||||
{
|
||||
NSObject nso = NSObject.Wrap(obj);
|
||||
NSObject nso = Wrap(obj);
|
||||
for(int i = 0; i < array.Count; i++)
|
||||
{
|
||||
if(array[i] == nso)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -197,39 +182,39 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
NSObject[] result = new NSObject[indexes.Length];
|
||||
Array.Sort(indexes);
|
||||
for (int i = 0; i < indexes.Length; i++)
|
||||
result[i] = array[indexes[i]];
|
||||
for(int i = 0; i < indexes.Length; i++) result[i] = array[indexes[i]];
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="Claunia.PropertyList.NSArray"/>.
|
||||
/// Determines whether the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="Claunia.PropertyList.NSArray"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray"/>; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(Object obj)
|
||||
/// <param name="obj">
|
||||
/// The <see cref="System.Object" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj.GetType().Equals(typeof(NSArray)))
|
||||
{
|
||||
return ArrayEquals(((NSArray)obj), this);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSObject nso = NSObject.Wrap(obj);
|
||||
if (nso.GetType().Equals(typeof(NSArray)))
|
||||
{
|
||||
return ArrayEquals(((NSArray)nso), this);
|
||||
}
|
||||
}
|
||||
if(obj.GetType().Equals(typeof(NSArray))) return ArrayEquals((NSArray)obj, this);
|
||||
|
||||
NSObject nso = Wrap(obj);
|
||||
if(nso.GetType().Equals(typeof(NSArray))) return ArrayEquals((NSArray)nso, this);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSArray" /> object.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.</returns>
|
||||
/// <returns>
|
||||
/// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 7;
|
||||
@@ -241,12 +226,13 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(xml, level);
|
||||
xml.Append("<array>");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
foreach(NSObject o in array)
|
||||
{
|
||||
o.ToXml(xml, level + 1);
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
}
|
||||
|
||||
Indent(xml, level);
|
||||
xml.Append("</array>");
|
||||
}
|
||||
@@ -254,28 +240,24 @@ namespace Claunia.PropertyList
|
||||
internal override void AssignIDs(BinaryPropertyListWriter outPlist)
|
||||
{
|
||||
base.AssignIDs(outPlist);
|
||||
foreach (NSObject obj in array)
|
||||
{
|
||||
obj.AssignIDs(outPlist);
|
||||
}
|
||||
foreach(NSObject obj in array) obj.AssignIDs(outPlist);
|
||||
}
|
||||
|
||||
internal override void ToBinary(BinaryPropertyListWriter outPlist)
|
||||
{
|
||||
outPlist.WriteIntHeader(0xA, array.Count);
|
||||
foreach (NSObject obj in array)
|
||||
{
|
||||
outPlist.WriteID(outPlist.GetID(obj));
|
||||
}
|
||||
foreach(NSObject obj in array) outPlist.WriteID(outPlist.GetID(obj));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Generates a valid ASCII property list which has this NSArray as its
|
||||
/// root object.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The generated property list complies with the format as
|
||||
/// described in https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
|
||||
/// described in
|
||||
/// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
|
||||
/// Property List Programming Guide - Old-Style ASCII Property Lists.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
@@ -292,9 +274,11 @@ namespace Claunia.PropertyList
|
||||
/// <para>
|
||||
/// Generates a valid ASCII property list in GnuStep format which has this
|
||||
/// NSArray as its root object.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The generated property list complies with
|
||||
/// the format as described in http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html
|
||||
/// the format as described in
|
||||
/// http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html
|
||||
/// GnuStep - NSPropertyListSerialization class documentation.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
@@ -315,8 +299,8 @@ namespace Claunia.PropertyList
|
||||
for(int i = 0; i < array.Count; i++)
|
||||
{
|
||||
Type objClass = array[i].GetType();
|
||||
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
|
||||
&& indexOfLastNewLine != ascii.Length)
|
||||
if((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) ||
|
||||
objClass.Equals(typeof(NSData))) && indexOfLastNewLine != ascii.Length)
|
||||
{
|
||||
ascii.Append(NEWLINE);
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
@@ -324,13 +308,11 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i != 0)
|
||||
ascii.Append(" ");
|
||||
if(i != 0) ascii.Append(" ");
|
||||
array[i].ToASCII(ascii, 0);
|
||||
}
|
||||
|
||||
if (i != array.Count - 1)
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
if(i != array.Count - 1) ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
|
||||
if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
|
||||
{
|
||||
@@ -338,6 +320,7 @@ namespace Claunia.PropertyList
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
}
|
||||
}
|
||||
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
|
||||
}
|
||||
|
||||
@@ -349,8 +332,8 @@ namespace Claunia.PropertyList
|
||||
for(int i = 0; i < array.Count; i++)
|
||||
{
|
||||
Type objClass = array[i].GetType();
|
||||
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
|
||||
&& indexOfLastNewLine != ascii.Length)
|
||||
if((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) ||
|
||||
objClass.Equals(typeof(NSData))) && indexOfLastNewLine != ascii.Length)
|
||||
{
|
||||
ascii.Append(NEWLINE);
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
@@ -358,13 +341,11 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i != 0)
|
||||
ascii.Append(" ");
|
||||
if(i != 0) ascii.Append(" ");
|
||||
array[i].ToASCIIGnuStep(ascii, 0);
|
||||
}
|
||||
|
||||
if (i != array.Count - 1)
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
if(i != array.Count - 1) ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
|
||||
if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
|
||||
{
|
||||
@@ -372,22 +353,27 @@ namespace Claunia.PropertyList
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
}
|
||||
}
|
||||
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSArray"/>.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSArray"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSArray" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
if (!(obj is NSArray))
|
||||
return false;
|
||||
if(!(obj is NSArray)) return false;
|
||||
|
||||
if (array.Count != ((NSArray)obj).array.Count)
|
||||
return false;
|
||||
if(array.Count != ((NSArray)obj).array.Count) return false;
|
||||
|
||||
for(int i = 0; i < array.Count; i++)
|
||||
if(!array[i].Equals(((NSArray)obj)[i]))
|
||||
@@ -397,4 +383,3 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// 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.Text;
|
||||
@@ -37,8 +38,7 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
// In the XML property list format, the base-64 encoded data is split across multiple lines.
|
||||
// Each line contains 68 characters.
|
||||
private const int DataLineLength = 68;
|
||||
readonly byte[] bytes;
|
||||
const int DataLineLength = 68;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the NSData object from the binary representation of it.
|
||||
@@ -46,7 +46,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="bytes">The raw data contained in the NSData object.</param>
|
||||
public NSData(byte[] bytes)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
Bytes = bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,7 +56,7 @@ namespace Claunia.PropertyList
|
||||
/// <exception cref="FormatException">When the given string is not a proper Base64 formatted string.</exception>
|
||||
public NSData(string base64)
|
||||
{
|
||||
bytes = Convert.FromBase64String(base64);
|
||||
Bytes = Convert.FromBase64String(base64);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,36 +67,21 @@ namespace Claunia.PropertyList
|
||||
/// <exception cref="IOException">If the file could not be read.</exception>
|
||||
public NSData(FileInfo file)
|
||||
{
|
||||
bytes = new byte[(int)file.Length];
|
||||
using (FileStream raf = file.OpenRead())
|
||||
{
|
||||
raf.Read(bytes, 0, (int)file.Length);
|
||||
}
|
||||
Bytes = new byte[(int)file.Length];
|
||||
using(FileStream raf = file.OpenRead()) raf.Read(Bytes, 0, (int)file.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The bytes contained in this NSData object.
|
||||
/// </summary>
|
||||
/// <value>The data as bytes</value>
|
||||
public byte[] Bytes
|
||||
{
|
||||
get
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
public byte[] Bytes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of data stored in this object.
|
||||
/// </summary>
|
||||
/// <value>The number of bytes contained in this object.</value>
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return bytes.Length;
|
||||
}
|
||||
}
|
||||
public int Length => Bytes.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Loads the bytes from this NSData object into a byte buffer.
|
||||
@@ -105,7 +90,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="length">The amount of data to copy</param>
|
||||
public void GetBytes(MemoryStream buf, int length)
|
||||
{
|
||||
buf.Write(bytes, 0, Math.Min(bytes.Length, length));
|
||||
buf.Write(Bytes, 0, Math.Min(Bytes.Length, length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -116,7 +101,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="rangeStop">The stop index.</param>
|
||||
public void GetBytes(MemoryStream buf, int rangeStart, int rangeStop)
|
||||
{
|
||||
buf.Write(bytes, rangeStart, Math.Min(bytes.Length, rangeStop));
|
||||
buf.Write(Bytes, rangeStart, Math.Min(Bytes.Length, rangeStop));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -125,29 +110,37 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The Base64 encoded data as a <c>string</c>.</returns>
|
||||
public string GetBase64EncodedData()
|
||||
{
|
||||
return Convert.ToBase64String(bytes);
|
||||
return Convert.ToBase64String(Bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="Claunia.PropertyList.NSData"/>.
|
||||
/// Determines whether the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSData" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="Claunia.PropertyList.NSData"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSData"/>; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(Object obj)
|
||||
/// <param name="obj">
|
||||
/// The <see cref="System.Object" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSData" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSData" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj.GetType().Equals(GetType()) && ArrayEquals(((NSData)obj).bytes, bytes);
|
||||
return obj.GetType().Equals(GetType()) && ArrayEquals(((NSData)obj).Bytes, Bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSData" /> object.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.</returns>
|
||||
/// <returns>
|
||||
/// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 5;
|
||||
hash = 67 * hash + bytes.GetHashCode();
|
||||
hash = 67 * hash + Bytes.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -155,25 +148,24 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(xml, level);
|
||||
xml.Append("<data>");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
string base64 = GetBase64EncodedData();
|
||||
foreach(string line in base64.Split('\n'))
|
||||
{
|
||||
for(int offset = 0; offset < base64.Length; offset += DataLineLength)
|
||||
{
|
||||
Indent(xml, level);
|
||||
xml.Append(line.Substring(offset, Math.Min(DataLineLength, line.Length - offset)));
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
}
|
||||
xml.Append(NEWLINE);
|
||||
}
|
||||
|
||||
Indent(xml, level);
|
||||
xml.Append("</data>");
|
||||
}
|
||||
|
||||
internal override void ToBinary(BinaryPropertyListWriter outPlist)
|
||||
{
|
||||
outPlist.WriteIntHeader(0x4, bytes.Length);
|
||||
outPlist.Write(bytes);
|
||||
outPlist.WriteIntHeader(0x4, Bytes.Length);
|
||||
outPlist.Write(Bytes);
|
||||
}
|
||||
|
||||
internal override void ToASCII(StringBuilder ascii, int level)
|
||||
@@ -181,20 +173,18 @@ namespace Claunia.PropertyList
|
||||
Indent(ascii, level);
|
||||
ascii.Append(ASCIIPropertyListParser.DATA_BEGIN_TOKEN);
|
||||
int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE, StringComparison.Ordinal);
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
for(int i = 0; i < Bytes.Length; i++)
|
||||
{
|
||||
int b = bytes[i] & 0xFF;
|
||||
ascii.Append(String.Format("{0:x2}", b));
|
||||
int b = Bytes[i] & 0xFF;
|
||||
ascii.Append(string.Format("{0:x2}", b));
|
||||
if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
|
||||
{
|
||||
ascii.Append(NEWLINE);
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
}
|
||||
else if ((i + 1) % 2 == 0 && i != bytes.Length - 1)
|
||||
{
|
||||
ascii.Append(" ");
|
||||
}
|
||||
else if((i + 1) % 2 == 0 && i != Bytes.Length - 1) ascii.Append(" ");
|
||||
}
|
||||
|
||||
ascii.Append(ASCIIPropertyListParser.DATA_END_TOKEN);
|
||||
}
|
||||
|
||||
@@ -204,28 +194,32 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSData"/>.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSData" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSData"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSData"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSData" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSData" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
if (!(obj is NSData))
|
||||
return false;
|
||||
if(!(obj is NSData)) return false;
|
||||
|
||||
return ArrayEquals(bytes, ((NSData)obj).Bytes);
|
||||
return ArrayEquals(Bytes, ((NSData)obj).Bytes);
|
||||
}
|
||||
|
||||
static public explicit operator byte[](NSData value)
|
||||
public static explicit operator byte[](NSData value)
|
||||
{
|
||||
return value.bytes;
|
||||
return value.Bytes;
|
||||
}
|
||||
|
||||
static public explicit operator NSData(byte[] value)
|
||||
public static explicit operator NSData(byte[] value)
|
||||
{
|
||||
return new NSData(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
// 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.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
@@ -34,8 +36,6 @@ namespace Claunia.PropertyList
|
||||
/// @author Natalia Portillo
|
||||
public class NSDate : NSObject
|
||||
{
|
||||
readonly DateTime date;
|
||||
|
||||
static readonly DateTime EPOCH = new DateTime(2001, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
// The datetime ends with 'Z', which indicates UTC time. To make sure .NET
|
||||
@@ -43,7 +43,43 @@ namespace Claunia.PropertyList
|
||||
static readonly string sdfDefault = "yyyy-MM-dd'T'HH:mm:ssK";
|
||||
static readonly string sdfGnuStep = "yyyy-MM-dd HH:mm:ss zzz";
|
||||
|
||||
static readonly System.Globalization.CultureInfo provider = System.Globalization.CultureInfo.InvariantCulture;
|
||||
static readonly CultureInfo provider = CultureInfo.InvariantCulture;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a date from its binary representation.
|
||||
/// </summary>
|
||||
/// <param name="bytes">bytes The date bytes</param>
|
||||
public NSDate(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
//dates are 8 byte big-endian double, seconds since the epoch
|
||||
Date = EPOCH.AddSeconds(BinaryPropertyListParser.ParseDouble(bytes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a date from its textual representation.
|
||||
/// That representation has the following pattern: <code>yyyy-MM-dd'T'HH:mm:ss'Z'</code>
|
||||
/// </summary>
|
||||
/// <param name="textRepresentation">The textual representation of the date (ISO 8601 format)</param>
|
||||
/// <exception cref="FormatException">When the date could not be parsed, i.e. it does not match the expected pattern.</exception>
|
||||
public NSDate(string textRepresentation)
|
||||
{
|
||||
Date = ParseDateString(textRepresentation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NSDate from a .NET DateTime
|
||||
/// </summary>
|
||||
/// <param name="d">The date</param>
|
||||
public NSDate(DateTime d)
|
||||
{
|
||||
Date = d;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <returns>The date.</returns>
|
||||
public DateTime Date { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parses the XML date string and creates a .NET DateTime object from it.
|
||||
@@ -53,14 +89,8 @@ namespace Claunia.PropertyList
|
||||
/// <exception cref="FormatException">Given string cannot be parsed</exception>
|
||||
static DateTime ParseDateString(string textRepresentation)
|
||||
{
|
||||
try
|
||||
{
|
||||
return DateTime.ParseExact(textRepresentation, sdfDefault, provider);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return DateTime.ParseExact(textRepresentation, sdfGnuStep, provider);
|
||||
}
|
||||
try { return DateTime.ParseExact(textRepresentation, sdfDefault, provider); }
|
||||
catch(FormatException) { return DateTime.ParseExact(textRepresentation, sdfGnuStep, provider); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,96 +117,62 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a date from its binary representation.
|
||||
/// Determines whether the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate" />.
|
||||
/// </summary>
|
||||
/// <param name="bytes">bytes The date bytes</param>
|
||||
public NSDate(ReadOnlySpan<byte> bytes)
|
||||
/// <param name="obj">
|
||||
/// The <see cref="System.Object" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
//dates are 8 byte big-endian double, seconds since the epoch
|
||||
date = EPOCH.AddSeconds(BinaryPropertyListParser.ParseDouble(bytes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a date from its textual representation.
|
||||
/// That representation has the following pattern: <code>yyyy-MM-dd'T'HH:mm:ss'Z'</code>
|
||||
/// </summary>
|
||||
/// <param name="textRepresentation">The textual representation of the date (ISO 8601 format)</param>
|
||||
/// <exception cref="FormatException">When the date could not be parsed, i.e. it does not match the expected pattern.</exception>
|
||||
public NSDate(String textRepresentation)
|
||||
{
|
||||
date = ParseDateString(textRepresentation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NSDate from a .NET DateTime
|
||||
/// </summary>
|
||||
/// <param name="d">The date</param>
|
||||
public NSDate(DateTime d)
|
||||
{
|
||||
date = d;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <returns>The date.</returns>
|
||||
public DateTime Date
|
||||
{
|
||||
get
|
||||
{
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="Claunia.PropertyList.NSDate"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="Claunia.PropertyList.NSDate"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate"/>; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(Object obj)
|
||||
{
|
||||
return obj.GetType().Equals(GetType()) && date.Equals(((NSDate)obj).Date);
|
||||
return obj.GetType().Equals(GetType()) && Date.Equals(((NSDate)obj).Date);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSDate" /> object.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.</returns>
|
||||
/// <returns>
|
||||
/// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return date.GetHashCode();
|
||||
return Date.GetHashCode();
|
||||
}
|
||||
|
||||
internal override void ToXml(StringBuilder xml, int level)
|
||||
{
|
||||
Indent(xml, level);
|
||||
xml.Append("<date>");
|
||||
xml.Append(MakeDateString(date));
|
||||
xml.Append(MakeDateString(Date));
|
||||
xml.Append("</date>");
|
||||
}
|
||||
|
||||
internal override void ToBinary(BinaryPropertyListWriter outPlist)
|
||||
{
|
||||
outPlist.Write(0x33);
|
||||
outPlist.WriteDouble((date - EPOCH).TotalSeconds);
|
||||
outPlist.WriteDouble((Date - EPOCH).TotalSeconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a string representation of the date.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the date.</returns>
|
||||
public override String ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return date.ToString();
|
||||
return Date.ToString();
|
||||
}
|
||||
|
||||
internal override void ToASCII(StringBuilder ascii, int level)
|
||||
{
|
||||
Indent(ascii, level);
|
||||
ascii.Append("\"");
|
||||
ascii.Append(MakeDateString(date));
|
||||
ascii.Append(MakeDateString(Date));
|
||||
ascii.Append("\"");
|
||||
}
|
||||
|
||||
@@ -184,35 +180,39 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(ascii, level);
|
||||
ascii.Append("<*D");
|
||||
ascii.Append(MakeDateStringGnuStep(date));
|
||||
ascii.Append(MakeDateStringGnuStep(Date));
|
||||
ascii.Append(">");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSDate"/>.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSDate"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDate" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
if (!(obj is NSDate))
|
||||
return false;
|
||||
if(!(obj is NSDate)) return false;
|
||||
|
||||
int equality = DateTime.Compare(date, ((NSDate)obj).Date);
|
||||
int equality = DateTime.Compare(Date, ((NSDate)obj).Date);
|
||||
|
||||
return equality == 0;
|
||||
}
|
||||
|
||||
static public explicit operator DateTime (NSDate value)
|
||||
public static explicit operator DateTime(NSDate value)
|
||||
{
|
||||
return value.date;
|
||||
return value.Date;
|
||||
}
|
||||
|
||||
static public explicit operator NSDate(DateTime value)
|
||||
public static explicit operator NSDate(DateTime value)
|
||||
{
|
||||
return new NSDate(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
// 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
@@ -32,9 +34,11 @@ namespace Claunia.PropertyList
|
||||
/// <para>
|
||||
/// A NSDictionary is a collection of keys and values, essentially a Dictionary.
|
||||
/// The keys are simple Strings whereas the values can be any kind of NSObject.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// You can access the keys through the function <see cref="Keys" />.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Access to the objects stored for each key is given through the function
|
||||
/// <see cref="ObjectForKey" />.
|
||||
/// </para>
|
||||
@@ -64,10 +68,31 @@ namespace Claunia.PropertyList
|
||||
/// <summary>
|
||||
/// Creates a new empty NSDictionary.
|
||||
/// </summary>
|
||||
public NSDictionary()
|
||||
: this(0)
|
||||
public NSDictionary() : this(0) { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is empty.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is empty; otherwise, <c>false</c>.</value>
|
||||
public bool IsEmpty => dict.Count == 0;
|
||||
|
||||
#region IEnumerable implementation
|
||||
/// <summary>
|
||||
/// Gets the enumerator.
|
||||
/// </summary>
|
||||
/// <returns>The enumerator.</returns>
|
||||
public IEnumerator<KeyValuePair<string, NSObject>> GetEnumerator()
|
||||
{
|
||||
return dict.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IEnumerable implementation
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return dict.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hashmap which stores the keys and values of this dictionary.
|
||||
@@ -91,24 +116,12 @@ namespace Claunia.PropertyList
|
||||
return dict.TryGetValue(key, out nso) ? nso : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is empty.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is empty; otherwise, <c>false</c>.</value>
|
||||
public bool IsEmpty
|
||||
{
|
||||
get
|
||||
{
|
||||
return dict.Count == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified object key is contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if key is contained, <c>false</c> otherwise.</returns>
|
||||
/// <param name="key">Key.</param>
|
||||
public bool ContainsKey(Object key)
|
||||
public bool ContainsKey(object key)
|
||||
{
|
||||
return key is string && dict.ContainsKey((string)key);
|
||||
}
|
||||
@@ -118,7 +131,7 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
/// <param name="key">Key.</param>
|
||||
/// <returns><c>true</c>, if removed, <c>false</c> otherwise.</returns>
|
||||
public bool Remove(Object key)
|
||||
public bool Remove(object key)
|
||||
{
|
||||
return key is string && dict.Remove((string)key);
|
||||
}
|
||||
@@ -128,10 +141,10 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
/// <param name="key">Key.</param>
|
||||
/// <returns>The object corresponding to the specified key, null if not found in the current instance.</returns>
|
||||
public NSObject Get(Object key)
|
||||
public NSObject Get(object key)
|
||||
{
|
||||
if (key is string)
|
||||
return ObjectForKey((string)key);
|
||||
if(key is string) return ObjectForKey((string)key);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -140,11 +153,11 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if value is contained, <c>false</c> otherwise.</returns>
|
||||
/// <param name="value">Object to search up in the current instance.</param>
|
||||
public bool ContainsValue(Object value)
|
||||
public bool ContainsValue(object value)
|
||||
{
|
||||
if (value == null)
|
||||
return false;
|
||||
NSObject wrap = NSObject.Wrap(value);
|
||||
if(value == null) return false;
|
||||
|
||||
NSObject wrap = Wrap(value);
|
||||
return dict.ContainsValue(wrap);
|
||||
}
|
||||
|
||||
@@ -153,12 +166,15 @@ namespace Claunia.PropertyList
|
||||
/// If the value is null, no operation will be performed on the dictionary.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="obj">The value. Supported object types are numbers, byte-arrays, dates, strings and arrays or sets of those.</param>
|
||||
public void Add(String key, Object obj)
|
||||
/// <param name="obj">
|
||||
/// The value. Supported object types are numbers, byte-arrays, dates, strings and arrays or sets of
|
||||
/// those.
|
||||
/// </param>
|
||||
public void Add(string key, object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
Add(key, NSObject.Wrap(obj));
|
||||
if(obj == null) return;
|
||||
|
||||
Add(key, Wrap(obj));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -199,14 +215,12 @@ namespace Claunia.PropertyList
|
||||
public bool ContainsValue(string val)
|
||||
{
|
||||
foreach(NSObject o in dict.Values)
|
||||
{
|
||||
if(o.GetType().Equals(typeof(NSString)))
|
||||
{
|
||||
NSString str = (NSString)o;
|
||||
if (str.Content.Equals(val))
|
||||
return true;
|
||||
}
|
||||
if(str.Content.Equals(val)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,14 +232,12 @@ namespace Claunia.PropertyList
|
||||
public bool ContainsValue(long val)
|
||||
{
|
||||
foreach(NSObject o in dict.Values)
|
||||
{
|
||||
if(o.GetType().Equals(typeof(NSNumber)))
|
||||
{
|
||||
NSNumber num = (NSNumber)o;
|
||||
if (num.isInteger() && num.ToInt() == val)
|
||||
return true;
|
||||
}
|
||||
if(num.isInteger() && num.ToInt() == val) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -237,14 +249,12 @@ namespace Claunia.PropertyList
|
||||
public bool ContainsValue(double val)
|
||||
{
|
||||
foreach(NSObject o in dict.Values)
|
||||
{
|
||||
if(o.GetType().Equals(typeof(NSNumber)))
|
||||
{
|
||||
NSNumber num = (NSNumber)o;
|
||||
if (num.isReal() && num.ToDouble() == val)
|
||||
return true;
|
||||
}
|
||||
if(num.isReal() && num.ToDouble() == val) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -256,14 +266,12 @@ namespace Claunia.PropertyList
|
||||
public bool ContainsValue(bool val)
|
||||
{
|
||||
foreach(NSObject o in dict.Values)
|
||||
{
|
||||
if(o.GetType().Equals(typeof(NSNumber)))
|
||||
{
|
||||
NSNumber num = (NSNumber)o;
|
||||
if (num.isBoolean() && num.ToBool() == val)
|
||||
return true;
|
||||
}
|
||||
if(num.isBoolean() && num.ToBool() == val) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -275,14 +283,12 @@ namespace Claunia.PropertyList
|
||||
public bool ContainsValue(DateTime val)
|
||||
{
|
||||
foreach(NSObject o in dict.Values)
|
||||
{
|
||||
if(o.GetType().Equals(typeof(NSDate)))
|
||||
{
|
||||
NSDate dat = (NSDate)o;
|
||||
if (dat.Date.Equals(val))
|
||||
return true;
|
||||
}
|
||||
if(dat.Date.Equals(val)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -294,30 +300,32 @@ namespace Claunia.PropertyList
|
||||
public bool ContainsValue(byte[] val)
|
||||
{
|
||||
foreach(NSObject o in dict.Values)
|
||||
{
|
||||
if(o.GetType().Equals(typeof(NSData)))
|
||||
{
|
||||
NSData dat = (NSData)o;
|
||||
if (ArrayEquals(dat.Bytes, val))
|
||||
return true;
|
||||
}
|
||||
if(ArrayEquals(dat.Bytes, val)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSDictionary"/>.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDictionary" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSDictionary"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDictionary"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSDictionary" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSDictionary" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
if (!(obj is NSDictionary))
|
||||
return false;
|
||||
if(!(obj is NSDictionary)) return false;
|
||||
|
||||
if (((NSDictionary)obj).dict.Count != dict.Count)
|
||||
return false;
|
||||
if(((NSDictionary)obj).dict.Count != dict.Count) return false;
|
||||
|
||||
bool found;
|
||||
|
||||
@@ -325,10 +333,8 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
NSObject nsoB;
|
||||
found = ((NSDictionary)obj).dict.TryGetValue(kvp.Key, out nsoB);
|
||||
if (!found)
|
||||
return false;
|
||||
if (!kvp.Value.Equals(nsoB))
|
||||
return false;
|
||||
if(!found) return false;
|
||||
if(!kvp.Value.Equals(nsoB)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -337,8 +343,10 @@ namespace Claunia.PropertyList
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSDictionary" /> object.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.</returns>
|
||||
/// <returns>
|
||||
/// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 7;
|
||||
@@ -350,7 +358,7 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(xml, level);
|
||||
xml.Append("<dict>");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
foreach(KeyValuePair<string, NSObject> kvp in dict)
|
||||
{
|
||||
Indent(xml, level + 1);
|
||||
@@ -363,15 +371,14 @@ namespace Claunia.PropertyList
|
||||
xml.Append(kvp.Key.Replace("]]>", "]]]]><![CDATA[>"));
|
||||
xml.Append("]]>");
|
||||
}
|
||||
else
|
||||
{
|
||||
xml.Append(kvp.Key);
|
||||
}
|
||||
else xml.Append(kvp.Key);
|
||||
|
||||
xml.Append("</key>");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
kvp.Value.ToXml(xml, level + 1);
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
}
|
||||
|
||||
Indent(xml, level);
|
||||
xml.Append("</dict>");
|
||||
}
|
||||
@@ -380,34 +387,23 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
base.AssignIDs(outPlist);
|
||||
|
||||
foreach (KeyValuePair<string, NSObject> entry in dict)
|
||||
{
|
||||
keys[entry.Key].AssignIDs(outPlist);
|
||||
}
|
||||
foreach(KeyValuePair<string, NSObject> entry in dict) keys[entry.Key].AssignIDs(outPlist);
|
||||
|
||||
foreach (KeyValuePair<string, NSObject> entry in dict)
|
||||
{
|
||||
entry.Value.AssignIDs(outPlist);
|
||||
}
|
||||
foreach(KeyValuePair<string, NSObject> entry in dict) entry.Value.AssignIDs(outPlist);
|
||||
}
|
||||
|
||||
internal override void ToBinary(BinaryPropertyListWriter outPlist)
|
||||
{
|
||||
outPlist.WriteIntHeader(0xD, dict.Count);
|
||||
foreach (KeyValuePair<String, NSObject> entry in dict)
|
||||
{
|
||||
outPlist.WriteID(outPlist.GetID(keys[entry.Key]));
|
||||
}
|
||||
foreach (KeyValuePair<String, NSObject> entry in dict)
|
||||
{
|
||||
outPlist.WriteID(outPlist.GetID(entry.Value));
|
||||
}
|
||||
foreach(KeyValuePair<string, NSObject> entry in dict) outPlist.WriteID(outPlist.GetID(keys[entry.Key]));
|
||||
foreach(KeyValuePair<string, NSObject> entry in dict) outPlist.WriteID(outPlist.GetID(entry.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a valid ASCII property list which has this NSDictionary as its
|
||||
/// root object. The generated property list complies with the format as
|
||||
/// described in https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
|
||||
/// described in
|
||||
/// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
|
||||
/// Property List Programming Guide - Old-Style ASCII Property Lists.
|
||||
/// </summary>
|
||||
/// <returns>ASCII representation of this object.</returns>
|
||||
@@ -422,7 +418,8 @@ namespace Claunia.PropertyList
|
||||
/// <summary>
|
||||
/// Generates a valid ASCII property list in GnuStep format which has this
|
||||
/// NSDictionary as its root object. The generated property list complies with
|
||||
/// the format as described in http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html
|
||||
/// the format as described in
|
||||
/// http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html
|
||||
/// GnuStep - NSPropertyListSerialization class documentation.
|
||||
/// </summary>
|
||||
/// <returns>GnuStep ASCII representation of this object.</returns>
|
||||
@@ -447,7 +444,8 @@ namespace Claunia.PropertyList
|
||||
ascii.Append(NSString.EscapeStringForASCII(key));
|
||||
ascii.Append("\" =");
|
||||
Type objClass = val.GetType();
|
||||
if (objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
|
||||
if(objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) ||
|
||||
objClass.Equals(typeof(NSData)))
|
||||
{
|
||||
ascii.Append(NEWLINE);
|
||||
val.ToASCII(ascii, level + 2);
|
||||
@@ -457,9 +455,11 @@ namespace Claunia.PropertyList
|
||||
ascii.Append(" ");
|
||||
val.ToASCII(ascii, 0);
|
||||
}
|
||||
|
||||
ascii.Append(ASCIIPropertyListParser.DICTIONARY_ITEM_DELIMITER_TOKEN);
|
||||
ascii.Append(NEWLINE);
|
||||
}
|
||||
|
||||
Indent(ascii, level);
|
||||
ascii.Append(ASCIIPropertyListParser.DICTIONARY_END_TOKEN);
|
||||
}
|
||||
@@ -477,7 +477,8 @@ namespace Claunia.PropertyList
|
||||
ascii.Append(NSString.EscapeStringForASCII(key));
|
||||
ascii.Append("\" =");
|
||||
Type objClass = val.GetType();
|
||||
if (objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
|
||||
if(objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) ||
|
||||
objClass.Equals(typeof(NSData)))
|
||||
{
|
||||
ascii.Append(NEWLINE);
|
||||
val.ToASCIIGnuStep(ascii, level + 2);
|
||||
@@ -487,15 +488,16 @@ namespace Claunia.PropertyList
|
||||
ascii.Append(" ");
|
||||
val.ToASCIIGnuStep(ascii, 0);
|
||||
}
|
||||
|
||||
ascii.Append(ASCIIPropertyListParser.DICTIONARY_ITEM_DELIMITER_TOKEN);
|
||||
ascii.Append(NEWLINE);
|
||||
}
|
||||
|
||||
Indent(ascii, level);
|
||||
ascii.Append(ASCIIPropertyListParser.DICTIONARY_END_TOKEN);
|
||||
}
|
||||
|
||||
#region IDictionary implementation
|
||||
|
||||
/// <summary>
|
||||
/// Add the specified key and value.
|
||||
/// </summary>
|
||||
@@ -554,16 +556,10 @@ namespace Claunia.PropertyList
|
||||
/// <param name="index">Index.</param>
|
||||
public NSObject this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return dict[index];
|
||||
}
|
||||
get => dict[index];
|
||||
set
|
||||
{
|
||||
if (!keys.ContainsKey(index))
|
||||
{
|
||||
keys.Add(index, new NSString(index));
|
||||
}
|
||||
if(!keys.ContainsKey(index)) keys.Add(index, new NSString(index));
|
||||
|
||||
dict[index] = value;
|
||||
}
|
||||
@@ -573,26 +569,13 @@ namespace Claunia.PropertyList
|
||||
/// Gets an array with all the keys contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>The keys.</value>
|
||||
public ICollection<string> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
return dict.Keys;
|
||||
}
|
||||
}
|
||||
public ICollection<string> Keys => dict.Keys;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an array with all the objects contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>The objects.</value>
|
||||
public ICollection<NSObject> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
return dict.Values;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<NSObject> Values => dict.Values;
|
||||
#endregion
|
||||
|
||||
#region ICollection implementation
|
||||
@@ -626,9 +609,13 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the <see cref="Dictionary{TKey, TValue}.ValueCollection"/> elements to an existing one-dimensional <see cref="Array"/>, starting at the specified array index.
|
||||
/// Copies the <see cref="Dictionary{TKey, TValue}.ValueCollection" /> elements to an existing one-dimensional
|
||||
/// <see cref="Array" />, starting at the specified array index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="Array"/> that is the destination of the elements copied from <see cref="Dictionary{TKey, TValue}.ValueCollection"/>. The <see cref="Array"/> must have zero-based indexing.</param>
|
||||
/// <param name="array">
|
||||
/// The one-dimensional <see cref="Array" /> that is the destination of the elements copied from
|
||||
/// <see cref="Dictionary{TKey, TValue}.ValueCollection" />. The <see cref="Array" /> must have zero-based indexing.
|
||||
/// </param>
|
||||
/// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
|
||||
public void CopyTo(KeyValuePair<string, NSObject>[] array, int arrayIndex)
|
||||
{
|
||||
@@ -651,48 +638,13 @@ namespace Claunia.PropertyList
|
||||
/// Gets the count of items in the current instance.
|
||||
/// </summary>
|
||||
/// <value>How many items are contained in the current instance.</value>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return dict.Count;
|
||||
}
|
||||
}
|
||||
public int Count => dict.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is read only.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is read only; otherwise, <c>false</c>.</value>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable implementation
|
||||
/// <summary>
|
||||
/// Gets the enumerator.
|
||||
/// </summary>
|
||||
/// <returns>The enumerator.</returns>
|
||||
public IEnumerator<KeyValuePair<string, NSObject>> GetEnumerator()
|
||||
{
|
||||
return dict.GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable implementation
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return dict.GetEnumerator();
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,10 @@
|
||||
// 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.Text;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -53,14 +54,14 @@ namespace Claunia.PropertyList
|
||||
/// Indicates that the number's value is bool.
|
||||
/// </summary>
|
||||
public const int BOOLEAN = 2;
|
||||
readonly bool boolValue;
|
||||
readonly double doubleValue;
|
||||
|
||||
readonly long longValue;
|
||||
|
||||
//Holds the current type of this number
|
||||
readonly int type;
|
||||
|
||||
readonly long longValue;
|
||||
readonly double doubleValue;
|
||||
readonly bool boolValue;
|
||||
|
||||
/// <summary>
|
||||
/// Parses integers and real numbers from their binary representation.
|
||||
/// <i>Note: real numbers are not yet supported.</i>
|
||||
@@ -82,9 +83,9 @@ namespace Claunia.PropertyList
|
||||
longValue = (long)Math.Round(doubleValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException("Type argument is not valid.");
|
||||
default: throw new ArgumentException("Type argument is not valid.");
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@@ -103,11 +104,9 @@ namespace Claunia.PropertyList
|
||||
longValue = (long)Math.Round(doubleValue);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentException("Type argument is not valid.");
|
||||
}
|
||||
default: { throw new ArgumentException("Type argument is not valid."); }
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@@ -120,8 +119,7 @@ namespace Claunia.PropertyList
|
||||
/// <seealso cref="double.Parse(string, IFormatProvider)" />
|
||||
public NSNumber(string text)
|
||||
{
|
||||
if (text == null)
|
||||
throw new ArgumentException("The given string is null and cannot be parsed as number.");
|
||||
if(text == null) throw new ArgumentException("The given string is null and cannot be parsed as number.");
|
||||
|
||||
long l;
|
||||
double d;
|
||||
@@ -131,6 +129,7 @@ namespace Claunia.PropertyList
|
||||
doubleValue = longValue = l;
|
||||
type = INTEGER;
|
||||
}
|
||||
|
||||
if(long.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out l))
|
||||
{
|
||||
doubleValue = longValue = l;
|
||||
@@ -144,8 +143,10 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isTrue = string.Equals(text, "true", StringComparison.CurrentCultureIgnoreCase) || string.Equals(text, "yes", StringComparison.CurrentCultureIgnoreCase);
|
||||
bool isFalse = string.Equals(text, "false", StringComparison.CurrentCultureIgnoreCase) || string.Equals(text, "no", StringComparison.CurrentCultureIgnoreCase);
|
||||
bool isTrue = string.Equals(text, "true", StringComparison.CurrentCultureIgnoreCase) ||
|
||||
string.Equals(text, "yes", StringComparison.CurrentCultureIgnoreCase);
|
||||
bool isFalse = string.Equals(text, "false", StringComparison.CurrentCultureIgnoreCase) ||
|
||||
string.Equals(text, "no", StringComparison.CurrentCultureIgnoreCase);
|
||||
|
||||
if(isTrue || isFalse)
|
||||
{
|
||||
@@ -153,9 +154,8 @@ namespace Claunia.PropertyList
|
||||
doubleValue = longValue = boolValue ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("The given string neither represents a double, an int nor a bool value.");
|
||||
}
|
||||
throw new
|
||||
ArgumentException("The given string neither represents a double, an int nor a bool value.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,6 +200,34 @@ namespace Claunia.PropertyList
|
||||
type = BOOLEAN;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the current <see cref="Claunia.PropertyList.NSNumber" /> to the specified object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// 0 if the numbers are equal, 1 if the current <see cref="Claunia.PropertyList.NSNumber" /> is greater
|
||||
/// than the argument and -1 if it is less, or the argument is not a number.
|
||||
/// </returns>
|
||||
/// <param name="o">Object to compare to the current <see cref="Claunia.PropertyList.NSNumber" />.</param>
|
||||
public int CompareTo(object o)
|
||||
{
|
||||
double x = ToDouble();
|
||||
double y;
|
||||
if(o is NSNumber)
|
||||
{
|
||||
NSNumber num = (NSNumber)o;
|
||||
y = num.ToDouble();
|
||||
return x < y ? -1 : (x == y ? 0 : 1);
|
||||
}
|
||||
|
||||
if(IsNumber(o))
|
||||
{
|
||||
y = GetDoubleFromObject(o);
|
||||
return x < y ? -1 : (x == y ? 0 : 1);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of this number's value.
|
||||
/// </summary>
|
||||
@@ -245,8 +273,8 @@ namespace Claunia.PropertyList
|
||||
/// <returns><c>true</c> if the value is true or non-zero, <c>false</c> otherwise.</returns>
|
||||
public bool ToBool()
|
||||
{
|
||||
if (type == BOOLEAN)
|
||||
return boolValue;
|
||||
if(type == BOOLEAN) return boolValue;
|
||||
|
||||
return longValue != 0;
|
||||
}
|
||||
|
||||
@@ -261,9 +289,11 @@ namespace Claunia.PropertyList
|
||||
|
||||
/// <summary>
|
||||
/// The number's int value.
|
||||
/// <i>Note: Even though the number's type might be INTEGER it can be larger than a Java int.
|
||||
/// <i>
|
||||
/// Note: Even though the number's type might be INTEGER it can be larger than a Java int.
|
||||
/// Use intValue() only if you are certain that it contains a number from the int range.
|
||||
/// Otherwise the value might be innaccurate.</i>
|
||||
/// Otherwise the value might be innaccurate.
|
||||
/// </i>
|
||||
/// </summary>
|
||||
/// <returns>The value of the number as int.</returns>
|
||||
public int ToInt()
|
||||
@@ -295,24 +325,28 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare to.</param>
|
||||
/// <returns>Whether the objects are equal in terms of numeric value and type.</returns>
|
||||
public override bool Equals(Object obj)
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is NSNumber))
|
||||
return false;
|
||||
if(!(obj is NSNumber)) return false;
|
||||
|
||||
NSNumber n = (NSNumber)obj;
|
||||
return type == n.type && longValue == n.longValue && doubleValue == n.doubleValue && boolValue == n.boolValue;
|
||||
return type == n.type && longValue == n.longValue && doubleValue == n.doubleValue &&
|
||||
boolValue == n.boolValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSNumber" /> object.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.</returns>
|
||||
/// <returns>
|
||||
/// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = type;
|
||||
hash = 37 * hash + (int)(longValue ^ ((uint)longValue >> 32));
|
||||
hash = 37 * hash + (int)(BitConverter.DoubleToInt64Bits(doubleValue) ^ ((uint)(BitConverter.DoubleToInt64Bits(doubleValue) >> 32)));
|
||||
hash = 37 * hash + (int)(BitConverter.DoubleToInt64Bits(doubleValue) ^
|
||||
(uint)(BitConverter.DoubleToInt64Bits(doubleValue) >> 32));
|
||||
hash = 37 * hash + (ToBool() ? 1 : 0);
|
||||
return hash;
|
||||
}
|
||||
@@ -325,22 +359,10 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case INTEGER:
|
||||
{
|
||||
return ToLong().ToString();
|
||||
}
|
||||
case REAL:
|
||||
{
|
||||
return ToDouble().ToString("R", CultureInfo.InvariantCulture);
|
||||
}
|
||||
case BOOLEAN:
|
||||
{
|
||||
return ToBool().ToString();
|
||||
}
|
||||
default:
|
||||
{
|
||||
return base.ToString();
|
||||
}
|
||||
case INTEGER: { return ToLong().ToString(); }
|
||||
case REAL: { return ToDouble().ToString("R", CultureInfo.InvariantCulture); }
|
||||
case BOOLEAN: { return ToBool().ToString(); }
|
||||
default: { return base.ToString(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,29 +382,16 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
xml.Append("<real>");
|
||||
|
||||
if (doubleValue == 0)
|
||||
{
|
||||
// 0 values appear to always roundtrip as 0.0,
|
||||
// but non-zero values do not include decimals if
|
||||
// not required (e.g. 10 -> "10")
|
||||
xml.Append("0.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// ToString() can truncate the decimals, so use "R". See
|
||||
// https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#the-round-trip-r-format-specifier
|
||||
xml.Append(ToDouble().ToString("R", CultureInfo.InvariantCulture));
|
||||
}
|
||||
if(doubleValue == 0) xml.Append("0.0");
|
||||
else xml.Append(ToDouble().ToString("R", CultureInfo.InvariantCulture));
|
||||
|
||||
xml.Append("</real>");
|
||||
break;
|
||||
}
|
||||
case BOOLEAN:
|
||||
{
|
||||
if (ToBool())
|
||||
xml.Append("<true/>");
|
||||
else
|
||||
xml.Append("<false/>");
|
||||
if(ToBool()) xml.Append("<true/>");
|
||||
else xml.Append("<false/>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -419,6 +428,7 @@ namespace Claunia.PropertyList
|
||||
outPlist.Write(0x13);
|
||||
outPlist.WriteBytes(ToLong(), 8);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case REAL:
|
||||
@@ -438,14 +448,8 @@ namespace Claunia.PropertyList
|
||||
internal override void ToASCII(StringBuilder ascii, int level)
|
||||
{
|
||||
Indent(ascii, level);
|
||||
if (type == BOOLEAN)
|
||||
{
|
||||
ascii.Append(boolValue ? "YES" : "NO");
|
||||
}
|
||||
else
|
||||
{
|
||||
ascii.Append(ToString());
|
||||
}
|
||||
if(type == BOOLEAN) ascii.Append(boolValue ? "YES" : "NO");
|
||||
else ascii.Append(ToString());
|
||||
}
|
||||
|
||||
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
|
||||
@@ -469,228 +473,177 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
case BOOLEAN:
|
||||
{
|
||||
if (boolValue)
|
||||
{
|
||||
ascii.Append("<*BY>");
|
||||
}
|
||||
else
|
||||
{
|
||||
ascii.Append("<*BN>");
|
||||
}
|
||||
if(boolValue) ascii.Append("<*BY>");
|
||||
else ascii.Append("<*BN>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the current <see cref="Claunia.PropertyList.NSNumber"/> to the specified object.
|
||||
/// </summary>
|
||||
/// <returns>0 if the numbers are equal, 1 if the current <see cref="Claunia.PropertyList.NSNumber"/> is greater
|
||||
/// than the argument and -1 if it is less, or the argument is not a number.</returns>
|
||||
/// <param name="o">Object to compare to the current <see cref="Claunia.PropertyList.NSNumber"/>.</param>
|
||||
public int CompareTo(Object o)
|
||||
{
|
||||
double x = ToDouble();
|
||||
double y;
|
||||
if (o is NSNumber)
|
||||
{
|
||||
NSNumber num = (NSNumber)o;
|
||||
y = num.ToDouble();
|
||||
return (x < y) ? -1 : ((x == y) ? 0 : 1);
|
||||
}
|
||||
if (IsNumber(o))
|
||||
{
|
||||
y = GetDoubleFromObject(o);
|
||||
return (x < y) ? -1 : ((x == y) ? 0 : 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an object is a number.
|
||||
/// Substitutes .NET's Number class comparison
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if it is a number.</returns>
|
||||
/// <param name="o">Object.</param>
|
||||
static bool IsNumber(Object o)
|
||||
static bool IsNumber(object o)
|
||||
{
|
||||
return o is sbyte
|
||||
|| o is byte
|
||||
|| o is short
|
||||
|| o is ushort
|
||||
|| o is int
|
||||
|| o is uint
|
||||
|| o is long
|
||||
|| o is ulong
|
||||
|| o is float
|
||||
|| o is double
|
||||
|| o is decimal;
|
||||
return o is sbyte || o is byte || o is short || o is ushort || o is int || o is uint || o is long ||
|
||||
o is ulong || o is float || o is double || o is decimal;
|
||||
}
|
||||
|
||||
static double GetDoubleFromObject(Object o)
|
||||
static double GetDoubleFromObject(object o)
|
||||
{
|
||||
if (o is sbyte)
|
||||
return (double)((sbyte)o);
|
||||
if (o is byte)
|
||||
return (double)((byte)o);
|
||||
if (o is short)
|
||||
return (double)((short)o);
|
||||
if (o is ushort)
|
||||
return (double)((ushort)o);
|
||||
if (o is int)
|
||||
return (double)((int)o);
|
||||
if (o is uint)
|
||||
return (double)((uint)o);
|
||||
if (o is long)
|
||||
return (double)((long)o);
|
||||
if (o is ulong)
|
||||
return (double)((ulong)o);
|
||||
if (o is float)
|
||||
return (double)((float)o);
|
||||
if (o is double)
|
||||
return (double)o;
|
||||
if (o is decimal)
|
||||
return (double)((decimal)o);
|
||||
if(o is sbyte) return (sbyte)o;
|
||||
if(o is byte) return (byte)o;
|
||||
if(o is short) return (short)o;
|
||||
if(o is ushort) return (ushort)o;
|
||||
if(o is int) return (int)o;
|
||||
if(o is uint) return (uint)o;
|
||||
if(o is long) return (long)o;
|
||||
if(o is ulong) return (ulong)o;
|
||||
if(o is float) return (float)o;
|
||||
if(o is double) return (double)o;
|
||||
if(o is decimal) return (double)(decimal)o;
|
||||
|
||||
return (double)0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSNumber"/>.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSNumber" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSNumber"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSNumber"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSNumber" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSNumber" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
if (!(obj is NSNumber))
|
||||
return false;
|
||||
if(!(obj is NSNumber)) return false;
|
||||
|
||||
if (((NSNumber)obj).GetNSNumberType() != type)
|
||||
return false;
|
||||
if(((NSNumber)obj).GetNSNumberType() != type) return false;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case INTEGER:
|
||||
return (longValue == ((NSNumber)obj).ToLong());
|
||||
case REAL:
|
||||
return (doubleValue == ((NSNumber)obj).ToDouble());
|
||||
case BOOLEAN:
|
||||
return (boolValue == ((NSNumber)obj).ToBool());
|
||||
default:
|
||||
return false;
|
||||
case INTEGER: return longValue == ((NSNumber)obj).ToLong();
|
||||
case REAL: return doubleValue == ((NSNumber)obj).ToDouble();
|
||||
case BOOLEAN: return boolValue == ((NSNumber)obj).ToBool();
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
static public explicit operator ulong(NSNumber value)
|
||||
public static explicit operator ulong(NSNumber value)
|
||||
{
|
||||
return (ulong)value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator long(NSNumber value)
|
||||
public static explicit operator long(NSNumber value)
|
||||
{
|
||||
return value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator uint(NSNumber value)
|
||||
public static explicit operator uint(NSNumber value)
|
||||
{
|
||||
return (uint)value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator int(NSNumber value)
|
||||
public static explicit operator int(NSNumber value)
|
||||
{
|
||||
return (int)value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator ushort(NSNumber value)
|
||||
public static explicit operator ushort(NSNumber value)
|
||||
{
|
||||
return (ushort)value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator short(NSNumber value)
|
||||
public static explicit operator short(NSNumber value)
|
||||
{
|
||||
return (short)value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator byte(NSNumber value)
|
||||
public static explicit operator byte(NSNumber value)
|
||||
{
|
||||
return (byte)value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator sbyte(NSNumber value)
|
||||
public static explicit operator sbyte(NSNumber value)
|
||||
{
|
||||
return (sbyte)value.longValue;
|
||||
}
|
||||
|
||||
static public explicit operator double(NSNumber value)
|
||||
public static explicit operator double(NSNumber value)
|
||||
{
|
||||
return value.doubleValue;
|
||||
}
|
||||
|
||||
static public explicit operator float(NSNumber value)
|
||||
public static explicit operator float(NSNumber value)
|
||||
{
|
||||
return (float)value.doubleValue;
|
||||
}
|
||||
|
||||
static public explicit operator bool(NSNumber value)
|
||||
public static explicit operator bool(NSNumber value)
|
||||
{
|
||||
return value.boolValue;
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(ulong value)
|
||||
public static explicit operator NSNumber(ulong value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(long value)
|
||||
public static explicit operator NSNumber(long value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(uint value)
|
||||
public static explicit operator NSNumber(uint value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(int value)
|
||||
public static explicit operator NSNumber(int value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(ushort value)
|
||||
public static explicit operator NSNumber(ushort value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(short value)
|
||||
public static explicit operator NSNumber(short value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(byte value)
|
||||
public static explicit operator NSNumber(byte value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(sbyte value)
|
||||
public static explicit operator NSNumber(sbyte value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(double value)
|
||||
public static explicit operator NSNumber(double value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(float value)
|
||||
public static explicit operator NSNumber(float value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
|
||||
static public explicit operator NSNumber(bool value)
|
||||
public static explicit operator NSNumber(bool value)
|
||||
{
|
||||
return new NSNumber(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
@@ -33,7 +33,8 @@ namespace Claunia.PropertyList
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Abstract interface for any object contained in a property list.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The names and functions of the various objects orient themselves
|
||||
/// towards Apple's Cocoa API.
|
||||
/// </para>
|
||||
@@ -47,21 +48,20 @@ namespace Claunia.PropertyList
|
||||
/// To maintain compatibility with the Apple format, only a newline character
|
||||
/// is used (as opposed to cr+lf which is normally used on Windows).
|
||||
/// </summary>
|
||||
readonly internal static string NEWLINE = "\n";
|
||||
|
||||
internal static readonly string NEWLINE = "\n";
|
||||
|
||||
/// <summary>
|
||||
/// The identation character used for generating the XML output. This is the
|
||||
/// tabulator character.
|
||||
/// </summary>
|
||||
readonly static string INDENT = "\t";
|
||||
static readonly string INDENT = "\t";
|
||||
|
||||
/// <summary>
|
||||
/// The maximum length of the text lines to be used when generating
|
||||
/// ASCII property lists. But this number is only a guideline it is not
|
||||
/// guaranteed that it will not be overstepped.
|
||||
/// </summary>
|
||||
internal readonly static int ASCII_LINE_LENGTH = 80;
|
||||
internal static readonly int ASCII_LINE_LENGTH = 80;
|
||||
|
||||
/// <summary>
|
||||
/// Generates the XML representation of the object (without XML headers or enclosing plist-tags).
|
||||
@@ -92,22 +92,23 @@ namespace Claunia.PropertyList
|
||||
public string ToXmlPropertyList()
|
||||
{
|
||||
StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
xml.Append("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
xml.Append("<plist version=\"1.0\">");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
ToXml(xml, 0);
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
xml.Append("</plist>");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
return xml.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the ASCII representation of this object.
|
||||
/// The generated ASCII representation does not end with a newline.
|
||||
/// Complies with https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
|
||||
/// Complies with
|
||||
/// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
|
||||
/// </summary>
|
||||
/// <param name="ascii">The StringBuilder onto which the ASCII representation is appended.</param>
|
||||
/// <param name="level">The indentation level of the object.</param>
|
||||
@@ -130,8 +131,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="level">The level of identation.</param>
|
||||
internal static void Indent(StringBuilder xml, int level)
|
||||
{
|
||||
for (int i = 0; i < level; i++)
|
||||
xml.Append(INDENT);
|
||||
for(int i = 0; i < level; i++) xml.Append(INDENT);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -180,13 +180,10 @@ namespace Claunia.PropertyList
|
||||
/// <param name="value">The value to represent as a NSObject.</param>
|
||||
/// <returns>A NSObject representing the given value.</returns>
|
||||
/// <exception cref="SystemException">When one of the objects contained in the array cannot be represented by a NSObject.</exception>
|
||||
public static NSArray Wrap(Object[] value)
|
||||
public static NSArray Wrap(object[] value)
|
||||
{
|
||||
NSArray arr = new NSArray(value.Length);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
arr.Add(Wrap(value[i]));
|
||||
}
|
||||
for(int i = 0; i < value.Length; i++) arr.Add(Wrap(value[i]));
|
||||
return arr;
|
||||
}
|
||||
|
||||
@@ -196,11 +193,10 @@ namespace Claunia.PropertyList
|
||||
/// <param name="value">The value to represent as a NSObject.</param>
|
||||
/// <returns>A NSObject representing the given value.</returns>
|
||||
/// <exception cref="SystemException">When one of the values contained in the map cannot be represented by a NSObject.</exception>
|
||||
public static NSDictionary Wrap(Dictionary<string, Object> value)
|
||||
public static NSDictionary Wrap(Dictionary<string, object> value)
|
||||
{
|
||||
NSDictionary dict = new NSDictionary();
|
||||
foreach (KeyValuePair<string, Object> kvp in value)
|
||||
dict.Add(kvp.Key, Wrap(kvp.Value));
|
||||
foreach(KeyValuePair<string, object> kvp in value) dict.Add(kvp.Key, Wrap(kvp.Value));
|
||||
return dict;
|
||||
}
|
||||
|
||||
@@ -210,147 +206,131 @@ namespace Claunia.PropertyList
|
||||
/// <param name="value">The value to represent as a NSObject.</param>
|
||||
/// <returns>A NSObject representing the given value.</returns>
|
||||
/// <exception cref="SystemException">When one of the values contained in the map cannot be represented by a NSObject.</exception>
|
||||
public static NSSet Wrap(List<Object> value)
|
||||
public static NSSet Wrap(List<object> value)
|
||||
{
|
||||
NSSet set = new NSSet();
|
||||
foreach (Object o in value)
|
||||
set.AddObject(Wrap(o));
|
||||
foreach(object o in value) set.AddObject(Wrap(o));
|
||||
return set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Creates a NSObject representing the given .NET Object.
|
||||
/// </para><para>
|
||||
/// Numerics of type <see cref="bool"/>, <see cref="int"/>, <see cref="long"/>, <see cref="short"/>, <see cref="byte"/>, <see cref="float"/> or <see cref="double"/> are wrapped as NSNumber objects.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Numerics of type <see cref="bool" />, <see cref="int" />, <see cref="long" />, <see cref="short" />,
|
||||
/// <see cref="byte" />, <see cref="float" /> or <see cref="double" /> are wrapped as NSNumber objects.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Strings are wrapped as <see cref="NSString" /> objects and byte arrays as <see cref="NSData" /> objects.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// DateTime objects are wrapped as <see cref="NSDate" /> objects.
|
||||
/// </para><para>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Serializable classes are serialized and their data is stored in <see cref="NSData" /> objects.
|
||||
/// </para><para>
|
||||
/// Arrays and Collection objects are converted to <see cref="NSArray"/> where each array member is wrapped into a <see cref="NSObject"/>.
|
||||
/// </para><para>
|
||||
/// Dictionaries are converted to <see cref="NSDictionary"/>. Each key is converted to a string and each value wrapped into a <see cref="NSObject"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Arrays and Collection objects are converted to <see cref="NSArray" /> where each array member is wrapped into a
|
||||
/// <see cref="NSObject" />.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Dictionaries are converted to <see cref="NSDictionary" />. Each key is converted to a string and each value
|
||||
/// wrapped into a <see cref="NSObject" />.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="o">The object to represent.</param>
|
||||
/// <returns>A NSObject equivalent to the given object.</returns>
|
||||
public static NSObject Wrap(Object o)
|
||||
public static NSObject Wrap(object o)
|
||||
{
|
||||
if (o == null)
|
||||
throw new NullReferenceException("A null object cannot be wrapped as a NSObject");
|
||||
if(o == null) throw new NullReferenceException("A null object cannot be wrapped as a NSObject");
|
||||
|
||||
if (o is NSObject)
|
||||
return (NSObject)o;
|
||||
if(o is NSObject) return (NSObject)o;
|
||||
|
||||
Type c = o.GetType();
|
||||
if (typeof(bool).Equals(c))
|
||||
{
|
||||
return Wrap((bool)o);
|
||||
}
|
||||
if (typeof(Byte).Equals(c))
|
||||
{
|
||||
return Wrap((int)(Byte)o);
|
||||
}
|
||||
if (typeof(short).Equals(c))
|
||||
{
|
||||
return Wrap((int)(short)o);
|
||||
}
|
||||
if (typeof(int).Equals(c))
|
||||
{
|
||||
return Wrap((int)(int)o);
|
||||
}
|
||||
if (typeof(long).IsAssignableFrom(c))
|
||||
{
|
||||
return Wrap((long)o);
|
||||
}
|
||||
if (typeof(float).Equals(c))
|
||||
{
|
||||
return Wrap((double)(float)o);
|
||||
}
|
||||
if (typeof(double).IsAssignableFrom(c))
|
||||
{
|
||||
return Wrap((double)o);
|
||||
}
|
||||
if (typeof(string).Equals(c))
|
||||
{
|
||||
return new NSString((string)o);
|
||||
}
|
||||
if (typeof(DateTime).Equals(c))
|
||||
{
|
||||
return new NSDate((DateTime)o);
|
||||
}
|
||||
if(typeof(bool).Equals(c)) return Wrap((bool)o);
|
||||
|
||||
if(typeof(byte).Equals(c)) return Wrap((byte)o);
|
||||
|
||||
if(typeof(short).Equals(c)) return Wrap((short)o);
|
||||
|
||||
if(typeof(int).Equals(c)) return Wrap((int)o);
|
||||
|
||||
if(typeof(long).IsAssignableFrom(c)) return Wrap((long)o);
|
||||
|
||||
if(typeof(float).Equals(c)) return Wrap((float)o);
|
||||
|
||||
if(typeof(double).IsAssignableFrom(c)) return Wrap((double)o);
|
||||
|
||||
if(typeof(string).Equals(c)) return new NSString((string)o);
|
||||
|
||||
if(typeof(DateTime).Equals(c)) return new NSDate((DateTime)o);
|
||||
|
||||
if(c.IsArray)
|
||||
{
|
||||
Type cc = c.GetElementType();
|
||||
if (cc.Equals(typeof(byte)))
|
||||
{
|
||||
return Wrap((byte[])o);
|
||||
}
|
||||
if(cc.Equals(typeof(byte))) return Wrap((byte[])o);
|
||||
|
||||
if(cc.Equals(typeof(bool)))
|
||||
{
|
||||
bool[] array = (bool[])o;
|
||||
NSArray nsa = new NSArray(array.Length);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
nsa.Add(Wrap(array[i]));
|
||||
for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i]));
|
||||
return nsa;
|
||||
}
|
||||
|
||||
if(cc.Equals(typeof(float)))
|
||||
{
|
||||
float[] array = (float[])o;
|
||||
NSArray nsa = new NSArray(array.Length);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
nsa.Add(Wrap(array[i]));
|
||||
for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i]));
|
||||
return nsa;
|
||||
}
|
||||
|
||||
if(cc.Equals(typeof(double)))
|
||||
{
|
||||
double[] array = (double[])o;
|
||||
NSArray nsa = new NSArray(array.Length);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
nsa.Add(Wrap(array[i]));
|
||||
for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i]));
|
||||
return nsa;
|
||||
}
|
||||
|
||||
if(cc.Equals(typeof(short)))
|
||||
{
|
||||
short[] array = (short[])o;
|
||||
NSArray nsa = new NSArray(array.Length);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
nsa.Add(Wrap(array[i]));
|
||||
for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i]));
|
||||
return nsa;
|
||||
}
|
||||
|
||||
if(cc.Equals(typeof(int)))
|
||||
{
|
||||
int[] array = (int[])o;
|
||||
NSArray nsa = new NSArray(array.Length);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
nsa.Add(Wrap(array[i]));
|
||||
for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i]));
|
||||
return nsa;
|
||||
}
|
||||
|
||||
if(cc.Equals(typeof(long)))
|
||||
{
|
||||
long[] array = (long[])o;
|
||||
NSArray nsa = new NSArray(array.Length);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
nsa.Add(Wrap(array[i]));
|
||||
for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i]));
|
||||
return nsa;
|
||||
}
|
||||
return Wrap((Object[])o);
|
||||
|
||||
return Wrap((object[])o);
|
||||
}
|
||||
if (typeof(Dictionary<string,Object>).IsAssignableFrom(c))
|
||||
|
||||
if(typeof(Dictionary<string, object>).IsAssignableFrom(c))
|
||||
{
|
||||
Dictionary<string,Object> netDict = (Dictionary<string,Object>)o;
|
||||
Dictionary<string, object> netDict = (Dictionary<string, object>)o;
|
||||
NSDictionary dict = new NSDictionary();
|
||||
foreach (KeyValuePair<string, Object> kvp in netDict)
|
||||
{
|
||||
dict.Add(kvp.Key, Wrap(kvp.Value));
|
||||
}
|
||||
foreach(KeyValuePair<string, object> kvp in netDict) dict.Add(kvp.Key, Wrap(kvp.Value));
|
||||
return dict;
|
||||
}
|
||||
if (typeof(List<Object>).IsAssignableFrom(c))
|
||||
return Wrap(((List<Object>)o).ToArray());
|
||||
|
||||
if(typeof(List<object>).IsAssignableFrom(c)) return Wrap(((List<object>)o).ToArray());
|
||||
|
||||
throw new PropertyListException(string.Format("Cannot wrap an object of type {0}.", o.GetType().Name));
|
||||
}
|
||||
@@ -359,47 +339,47 @@ namespace Claunia.PropertyList
|
||||
/// Converts this NSObject into an equivalent object
|
||||
/// of the .NET Runtime Environment.
|
||||
/// <para><see cref="NSArray" /> objects are converted to arrays.</para>
|
||||
/// <para><see cref="NSDictionary"/> objects are converted to objects extending the <see cref="Dictionary{TKey, TValue}"/> class.</para>
|
||||
/// <para>
|
||||
/// <see cref="NSDictionary" /> objects are converted to objects extending the
|
||||
/// <see cref="Dictionary{TKey, TValue}" /> class.
|
||||
/// </para>
|
||||
/// <para><see cref="NSSet" /> objects are converted to objects extending the <see cref="List{NSObject}" /> class.</para>
|
||||
/// <para><see cref="NSNumber"/> objects are converted to primitive number values (<see cref="int"/>, <see cref="long"/>, <see cref="double"/> or <see cref="bool"/>).</para>
|
||||
/// <para>
|
||||
/// <see cref="NSNumber" /> objects are converted to primitive number values (<see cref="int" />,
|
||||
/// <see cref="long" />, <see cref="double" /> or <see cref="bool" />).
|
||||
/// </para>
|
||||
/// <para><see cref="NSString" /> objects are converted to <see cref="string" /> objects.</para>
|
||||
/// <para><see cref="NSData" /> objects are converted to <see cref="byte" /> arrays.</para>
|
||||
/// <para><see cref="NSDate" /> objects are converted to <see cref="System.DateTime" /> objects.</para>
|
||||
/// <para><see cref="UID" /> objects are converted to <see cref="byte" /> arrays.</para>
|
||||
/// </summary>
|
||||
/// <returns>A native .NET object representing this NSObject's value.</returns>
|
||||
public Object ToObject()
|
||||
public object ToObject()
|
||||
{
|
||||
if(this is NSArray)
|
||||
{
|
||||
var nsArray = (NSArray)this;
|
||||
NSArray nsArray = (NSArray)this;
|
||||
object[] array = new object[nsArray.Count];
|
||||
for (int i = 0; i < nsArray.Count; i++)
|
||||
{
|
||||
array[i] = nsArray[i].ToObject();
|
||||
}
|
||||
for(int i = 0; i < nsArray.Count; i++) array[i] = nsArray[i].ToObject();
|
||||
return array;
|
||||
}
|
||||
|
||||
if(this is NSDictionary)
|
||||
{
|
||||
Dictionary<string, NSObject> dictA = ((NSDictionary)this).GetDictionary();
|
||||
Dictionary<string, Object> dictB = new Dictionary<string, Object>(dictA.Count);
|
||||
foreach (KeyValuePair<string, NSObject> kvp in dictA)
|
||||
{
|
||||
dictB.Add(kvp.Key, kvp.Value.ToObject());
|
||||
}
|
||||
Dictionary<string, object> dictB = new Dictionary<string, object>(dictA.Count);
|
||||
foreach(KeyValuePair<string, NSObject> kvp in dictA) dictB.Add(kvp.Key, kvp.Value.ToObject());
|
||||
return dictB;
|
||||
}
|
||||
|
||||
if(this is NSSet)
|
||||
{
|
||||
List<NSObject> setA = ((NSSet)this).GetSet();
|
||||
List<Object> setB = new List<Object>();
|
||||
foreach (NSObject o in setA)
|
||||
{
|
||||
setB.Add(o.ToObject());
|
||||
}
|
||||
List<object> setB = new List<object>();
|
||||
foreach(NSObject o in setA) setB.Add(o.ToObject());
|
||||
return setB;
|
||||
}
|
||||
|
||||
if(this is NSNumber)
|
||||
{
|
||||
NSNumber num = (NSNumber)this;
|
||||
@@ -408,34 +388,24 @@ namespace Claunia.PropertyList
|
||||
case NSNumber.INTEGER:
|
||||
{
|
||||
long longVal = num.ToLong();
|
||||
if (longVal > int.MaxValue || longVal < int.MinValue)
|
||||
return longVal;
|
||||
if(longVal > int.MaxValue || longVal < int.MinValue) return longVal;
|
||||
|
||||
return num.ToInt();
|
||||
}
|
||||
case NSNumber.REAL:
|
||||
return num.ToDouble();
|
||||
case NSNumber.BOOLEAN:
|
||||
return num.ToBool();
|
||||
default :
|
||||
return num.ToDouble();
|
||||
case NSNumber.REAL: return num.ToDouble();
|
||||
case NSNumber.BOOLEAN: return num.ToBool();
|
||||
default: return num.ToDouble();
|
||||
}
|
||||
}
|
||||
if (this is NSString)
|
||||
{
|
||||
return ((NSString)this).Content;
|
||||
}
|
||||
if (this is NSData)
|
||||
{
|
||||
return ((NSData)this).Bytes;
|
||||
}
|
||||
if (this is NSDate)
|
||||
{
|
||||
return ((NSDate)this).Date;
|
||||
}
|
||||
if (this is UID)
|
||||
{
|
||||
return ((UID)this).Bytes;
|
||||
}
|
||||
|
||||
if(this is NSString) return ((NSString)this).Content;
|
||||
|
||||
if(this is NSData) return ((NSData)this).Bytes;
|
||||
|
||||
if(this is NSDate) return ((NSDate)this).Date;
|
||||
|
||||
if(this is UID) return ((UID)this).Bytes;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -446,8 +416,10 @@ namespace Claunia.PropertyList
|
||||
for(int i = 0; i < arrayA.Length; i++)
|
||||
if(arrayA[i] != arrayB[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -456,24 +428,26 @@ namespace Claunia.PropertyList
|
||||
if(arrayA.Count == arrayB.Count)
|
||||
{
|
||||
for(int i = 0; i < arrayA.Count; i++)
|
||||
{
|
||||
if(arrayA[i] != arrayB[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the specific NSObject is the same as the NSObject overriding this method.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSObject"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSObject"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSObject" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSObject" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public abstract bool Equals(NSObject obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,10 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
@@ -32,8 +33,9 @@ namespace Claunia.PropertyList
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// A set is an interface to an unordered collection of objects.
|
||||
/// </para><para>
|
||||
/// This implementation uses a <see cref="List{NSObject}"/>as the underlying
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This implementation uses a <see cref="List{T}" />as the underlying
|
||||
/// data structure.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
@@ -63,7 +65,6 @@ namespace Claunia.PropertyList
|
||||
set = new List<NSObject>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a set and fill it with the given objects.
|
||||
/// </summary>
|
||||
@@ -82,8 +83,30 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
this.ordered = ordered;
|
||||
set = new List<NSObject>(objects);
|
||||
if (ordered)
|
||||
set.Sort();
|
||||
if(ordered) set.Sort();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements in the set.
|
||||
/// </summary>
|
||||
/// <value>The number of elements in the set.</value>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock(set) return set.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator object that lets you iterate over all elements of the set.
|
||||
/// This is the equivalent to <c>objectEnumerator</c> in the Cocoa implementation
|
||||
/// of NSSet.
|
||||
/// </summary>
|
||||
/// <returns>The iterator for the set.</returns>
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
lock(set) return set.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -95,8 +118,7 @@ namespace Claunia.PropertyList
|
||||
lock(set)
|
||||
{
|
||||
set.Add(obj);
|
||||
if (ordered)
|
||||
set.Sort();
|
||||
if(ordered) set.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +131,7 @@ namespace Claunia.PropertyList
|
||||
lock(set)
|
||||
{
|
||||
set.Remove(obj);
|
||||
if (ordered)
|
||||
set.Sort();
|
||||
if(ordered) set.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +141,7 @@ namespace Claunia.PropertyList
|
||||
/// <returns>An array of all objects in the set.</returns>
|
||||
public NSObject[] AllObjects()
|
||||
{
|
||||
lock (set)
|
||||
{
|
||||
return set.ToArray();
|
||||
}
|
||||
lock(set) return set.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -133,10 +151,7 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The first object in the set, or <c>null</c> if the set is empty.</returns>
|
||||
public NSObject AnyObject()
|
||||
{
|
||||
lock (set)
|
||||
{
|
||||
return set.Count == 0 ? null : set[0];
|
||||
}
|
||||
lock(set) return set.Count == 0 ? null : set[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -160,10 +175,9 @@ namespace Claunia.PropertyList
|
||||
lock(set)
|
||||
{
|
||||
foreach(NSObject o in set)
|
||||
{
|
||||
if(o.Equals(obj))
|
||||
return o;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -178,10 +192,9 @@ namespace Claunia.PropertyList
|
||||
lock(set)
|
||||
{
|
||||
foreach(NSObject o in set)
|
||||
{
|
||||
if(otherSet.ContainsObject(o))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -196,25 +209,10 @@ namespace Claunia.PropertyList
|
||||
lock(set)
|
||||
{
|
||||
foreach(NSObject o in set)
|
||||
{
|
||||
if(!otherSet.ContainsObject(o))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator object that lets you iterate over all elements of the set.
|
||||
/// This is the equivalent to <c>objectEnumerator</c> in the Cocoa implementation
|
||||
/// of NSSet.
|
||||
/// </summary>
|
||||
/// <returns>The iterator for the set.</returns>
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
lock (set)
|
||||
{
|
||||
return set.GetEnumerator();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,8 +228,10 @@ namespace Claunia.PropertyList
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSSet" /> object.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.</returns>
|
||||
/// <returns>
|
||||
/// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 7;
|
||||
@@ -240,40 +240,27 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="Claunia.PropertyList.NSSet"/>.
|
||||
/// Determines whether the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="Claunia.PropertyList.NSSet"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet"/>; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(Object obj)
|
||||
/// <param name="obj">
|
||||
/// The <see cref="System.Object" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (GetType() != obj.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(obj == null) return false;
|
||||
|
||||
if(GetType() != obj.GetType()) return false;
|
||||
|
||||
NSSet other = (NSSet)obj;
|
||||
return !(set != other.set && (set == null || !set.Equals(other.set)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements in the set.
|
||||
/// </summary>
|
||||
/// <value>The number of elements in the set.</value>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (set)
|
||||
{
|
||||
return set.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the XML representantion for this set.
|
||||
/// There is no official XML representation specified for sets.
|
||||
@@ -285,14 +272,14 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(xml, level);
|
||||
xml.Append("<array>");
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
if (ordered)
|
||||
set.Sort();
|
||||
xml.Append(NEWLINE);
|
||||
if(ordered) set.Sort();
|
||||
foreach(NSObject o in set)
|
||||
{
|
||||
o.ToXml(xml, level + 1);
|
||||
xml.Append(NSObject.NEWLINE);
|
||||
xml.Append(NEWLINE);
|
||||
}
|
||||
|
||||
Indent(xml, level);
|
||||
xml.Append("</array>");
|
||||
}
|
||||
@@ -300,10 +287,7 @@ namespace Claunia.PropertyList
|
||||
internal override void AssignIDs(BinaryPropertyListWriter outPlist)
|
||||
{
|
||||
base.AssignIDs(outPlist);
|
||||
foreach (NSObject obj in set)
|
||||
{
|
||||
obj.AssignIDs(outPlist);
|
||||
}
|
||||
foreach(NSObject obj in set) obj.AssignIDs(outPlist);
|
||||
}
|
||||
|
||||
internal override void ToBinary(BinaryPropertyListWriter outPlist)
|
||||
@@ -313,14 +297,9 @@ namespace Claunia.PropertyList
|
||||
set.Sort();
|
||||
outPlist.WriteIntHeader(0xB, set.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
outPlist.WriteIntHeader(0xC, set.Count);
|
||||
}
|
||||
foreach (NSObject obj in set)
|
||||
{
|
||||
outPlist.WriteID(outPlist.GetID(obj));
|
||||
}
|
||||
else outPlist.WriteIntHeader(0xC, set.Count);
|
||||
|
||||
foreach(NSObject obj in set) outPlist.WriteID(outPlist.GetID(obj));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -333,16 +312,15 @@ namespace Claunia.PropertyList
|
||||
internal override void ToASCII(StringBuilder ascii, int level)
|
||||
{
|
||||
Indent(ascii, level);
|
||||
if (ordered)
|
||||
set.Sort();
|
||||
if(ordered) set.Sort();
|
||||
NSObject[] array = AllObjects();
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
|
||||
int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE, StringComparison.Ordinal);
|
||||
for(int i = 0; i < array.Length; i++)
|
||||
{
|
||||
Type objClass = array[i].GetType();
|
||||
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
|
||||
&& indexOfLastNewLine != ascii.Length)
|
||||
if((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) ||
|
||||
objClass.Equals(typeof(NSData))) && indexOfLastNewLine != ascii.Length)
|
||||
{
|
||||
ascii.Append(NEWLINE);
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
@@ -350,13 +328,11 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i != 0)
|
||||
ascii.Append(" ");
|
||||
if(i != 0) ascii.Append(" ");
|
||||
array[i].ToASCII(ascii, 0);
|
||||
}
|
||||
|
||||
if (i != array.Length - 1)
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
if(i != array.Length - 1) ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
|
||||
if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
|
||||
{
|
||||
@@ -364,6 +340,7 @@ namespace Claunia.PropertyList
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
}
|
||||
}
|
||||
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
|
||||
}
|
||||
|
||||
@@ -377,16 +354,15 @@ namespace Claunia.PropertyList
|
||||
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
|
||||
{
|
||||
Indent(ascii, level);
|
||||
if (ordered)
|
||||
set.Sort();
|
||||
if(ordered) set.Sort();
|
||||
NSObject[] array = AllObjects();
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
|
||||
int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE, StringComparison.Ordinal);
|
||||
for(int i = 0; i < array.Length; i++)
|
||||
{
|
||||
Type objClass = array[i].GetType();
|
||||
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
|
||||
&& indexOfLastNewLine != ascii.Length)
|
||||
if((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) ||
|
||||
objClass.Equals(typeof(NSData))) && indexOfLastNewLine != ascii.Length)
|
||||
{
|
||||
ascii.Append(NEWLINE);
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
@@ -394,13 +370,11 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i != 0)
|
||||
ascii.Append(" ");
|
||||
if(i != 0) ascii.Append(" ");
|
||||
array[i].ToASCIIGnuStep(ascii, 0);
|
||||
}
|
||||
|
||||
if (i != array.Length - 1)
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
if(i != array.Length - 1) ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
|
||||
|
||||
if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
|
||||
{
|
||||
@@ -408,22 +382,27 @@ namespace Claunia.PropertyList
|
||||
indexOfLastNewLine = ascii.Length;
|
||||
}
|
||||
}
|
||||
|
||||
ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSSet"/>.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSSet"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSSet" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
if (!(obj is NSSet))
|
||||
return false;
|
||||
if(!(obj is NSSet)) return false;
|
||||
|
||||
if (set.Count != ((NSSet)obj).Count)
|
||||
return false;
|
||||
if(set.Count != ((NSSet)obj).Count) return false;
|
||||
|
||||
foreach(NSObject objS in (NSSet)obj)
|
||||
if(!set.Contains(objS))
|
||||
@@ -433,4 +412,3 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// 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.Text;
|
||||
|
||||
@@ -34,7 +35,7 @@ namespace Claunia.PropertyList
|
||||
/// @author Natalia Portillo
|
||||
public class NSString : NSObject, IComparable
|
||||
{
|
||||
string content;
|
||||
static Encoding asciiEncoder, utf16beEncoder, utf8Encoder;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NSString from its binary representation.
|
||||
@@ -42,10 +43,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="bytes">The binary representation.</param>
|
||||
/// <param name="encoding">The encoding of the binary representation, the name of a supported charset.</param>
|
||||
/// <exception cref="ArgumentException">The encoding charset is invalid or not supported by the underlying platform.</exception>
|
||||
public NSString(ReadOnlySpan<byte> bytes, String encoding)
|
||||
: this(bytes, Encoding.GetEncoding(encoding))
|
||||
{
|
||||
}
|
||||
public NSString(ReadOnlySpan<byte> bytes, string encoding) : this(bytes, Encoding.GetEncoding(encoding)) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NSString from its binary representation.
|
||||
@@ -56,9 +54,9 @@ namespace Claunia.PropertyList
|
||||
public NSString(ReadOnlySpan<byte> bytes, Encoding encoding)
|
||||
{
|
||||
#if NATIVE_SPAN
|
||||
content = encoding.GetString(bytes);
|
||||
Content = encoding.GetString(bytes);
|
||||
#else
|
||||
content = encoding.GetString(bytes.ToArray());
|
||||
Content = encoding.GetString(bytes.ToArray());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -68,17 +66,26 @@ namespace Claunia.PropertyList
|
||||
/// <param name="text">The string that will be contained in the NSString.</param>
|
||||
public NSString(string text)
|
||||
{
|
||||
content = text;
|
||||
Content = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets this strings content.
|
||||
/// </summary>
|
||||
/// <returns>This NSString as .NET string object.</returns>
|
||||
public string Content
|
||||
public string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the current <see cref="Claunia.PropertyList.NSString" /> to the specified object.
|
||||
/// </summary>
|
||||
/// <returns>A 32-bit signed integer that indicates the lexical relationship between the two comparands.</returns>
|
||||
/// <param name="o">Object to compare to the current <see cref="Claunia.PropertyList.NSString" />.</param>
|
||||
public int CompareTo(object o)
|
||||
{
|
||||
get { return this.content; }
|
||||
set { this.content = value; }
|
||||
if(o is NSString) return string.Compare(Content, ((NSString)o).Content, StringComparison.Ordinal);
|
||||
if(o is string) return string.Compare(Content, (string)o, StringComparison.Ordinal);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,7 +103,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="s">The string to append.</param>
|
||||
public void Append(string s)
|
||||
{
|
||||
content += s;
|
||||
Content += s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,7 +112,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="s">The string to prepend.</param>
|
||||
public void Prepend(string s)
|
||||
{
|
||||
content = s + content;
|
||||
Content = s + Content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -118,26 +125,34 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="Claunia.PropertyList.NSString"/>.
|
||||
/// Determines whether the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSString" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="Claunia.PropertyList.NSString"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSString"/>; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(Object obj)
|
||||
/// <param name="obj">
|
||||
/// The <see cref="System.Object" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSString" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSString" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is NSString))
|
||||
return false;
|
||||
return content.Equals(((NSString)obj).content);
|
||||
if(!(obj is NSString)) return false;
|
||||
|
||||
return Content.Equals(((NSString)obj).Content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSString" /> object.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.</returns>
|
||||
/// <returns>
|
||||
/// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||
/// hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return content.GetHashCode();
|
||||
return Content.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -146,11 +161,9 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The NSString's contents.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return content;
|
||||
return Content;
|
||||
}
|
||||
|
||||
static Encoding asciiEncoder, utf16beEncoder, utf8Encoder;
|
||||
|
||||
internal override void ToXml(StringBuilder xml, int level)
|
||||
{
|
||||
Indent(xml, level);
|
||||
@@ -159,13 +172,12 @@ namespace Claunia.PropertyList
|
||||
//Make sure that the string is encoded in UTF-8 for the XML output
|
||||
lock(typeof(NSString))
|
||||
{
|
||||
if (utf8Encoder == null)
|
||||
utf8Encoder = Encoding.GetEncoding("UTF-8");
|
||||
if(utf8Encoder == null) utf8Encoder = Encoding.GetEncoding("UTF-8");
|
||||
|
||||
try
|
||||
{
|
||||
byte[] bytes = utf8Encoder.GetBytes(content);
|
||||
content = utf8Encoder.GetString(bytes);
|
||||
byte[] bytes = utf8Encoder.GetBytes(Content);
|
||||
Content = utf8Encoder.GetString(bytes);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
@@ -175,16 +187,14 @@ namespace Claunia.PropertyList
|
||||
|
||||
//According to http://www.w3.org/TR/REC-xml/#syntax node values must not
|
||||
//contain the characters < or &. Also the > character should be escaped.
|
||||
if (content.Contains("&") || content.Contains("<") || content.Contains(">"))
|
||||
if(Content.Contains("&") || Content.Contains("<") || Content.Contains(">"))
|
||||
{
|
||||
xml.Append("<![CDATA[");
|
||||
xml.Append(content.Replace("]]>", "]]]]><![CDATA[>"));
|
||||
xml.Append(Content.Replace("]]>", "]]]]><![CDATA[>"));
|
||||
xml.Append("]]>");
|
||||
}
|
||||
else
|
||||
{
|
||||
xml.Append(content);
|
||||
}
|
||||
else xml.Append(Content);
|
||||
|
||||
xml.Append("</string>");
|
||||
}
|
||||
|
||||
@@ -196,23 +206,24 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
if(asciiEncoder == null)
|
||||
// Not much use, because some characters do not fallback to exception, even if not ASCII
|
||||
asciiEncoder = Encoding.GetEncoding("ascii", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
|
||||
asciiEncoder = Encoding.GetEncoding("ascii", EncoderFallback.ExceptionFallback,
|
||||
DecoderFallback.ExceptionFallback);
|
||||
|
||||
if (IsASCIIEncodable(content))
|
||||
if(IsASCIIEncodable(Content))
|
||||
{
|
||||
kind = 0x5; // standard ASCII
|
||||
byteBuf = asciiEncoder.GetBytes(content);
|
||||
byteBuf = asciiEncoder.GetBytes(Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (utf16beEncoder == null)
|
||||
utf16beEncoder = Encoding.BigEndianUnicode;
|
||||
if(utf16beEncoder == null) utf16beEncoder = Encoding.BigEndianUnicode;
|
||||
|
||||
kind = 0x6; // UTF-16-BE
|
||||
byteBuf = utf16beEncoder.GetBytes(content);
|
||||
byteBuf = utf16beEncoder.GetBytes(Content);
|
||||
}
|
||||
}
|
||||
outPlist.WriteIntHeader(kind, content.Length);
|
||||
|
||||
outPlist.WriteIntHeader(kind, Content.Length);
|
||||
outPlist.Write(byteBuf);
|
||||
}
|
||||
|
||||
@@ -224,7 +235,7 @@ namespace Claunia.PropertyList
|
||||
//non-ASCII characters are not escaped but simply written into the
|
||||
//file, thus actually violating the ASCII plain text format.
|
||||
//We will escape the string anyway because current Xcode project files (ASCII property lists) also escape their strings.
|
||||
ascii.Append(EscapeStringForASCII(content));
|
||||
ascii.Append(EscapeStringForASCII(Content));
|
||||
ascii.Append("\"");
|
||||
}
|
||||
|
||||
@@ -232,7 +243,7 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(ascii, level);
|
||||
ascii.Append("\"");
|
||||
ascii.Append(EscapeStringForASCII(content));
|
||||
ascii.Append(EscapeStringForASCII(Content));
|
||||
ascii.Append("\"");
|
||||
}
|
||||
|
||||
@@ -246,93 +257,61 @@ namespace Claunia.PropertyList
|
||||
string outString = "";
|
||||
char[] cArray = s.ToCharArray();
|
||||
foreach(char c in cArray)
|
||||
{
|
||||
if(c > 127)
|
||||
{
|
||||
//non-ASCII Unicode
|
||||
outString += "\\U";
|
||||
string hex = String.Format("{0:x}", c);
|
||||
while (hex.Length < 4)
|
||||
hex = "0" + hex;
|
||||
string hex = string.Format("{0:x}", c);
|
||||
while(hex.Length < 4) hex = "0" + hex;
|
||||
outString += hex;
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
outString += "\\\\";
|
||||
}
|
||||
else if (c == '\"')
|
||||
{
|
||||
outString += "\\\"";
|
||||
}
|
||||
else if (c == '\b')
|
||||
{
|
||||
outString += "\\b";
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
outString += "\\n";
|
||||
}
|
||||
else if (c == '\r')
|
||||
{
|
||||
outString += "\\r";
|
||||
}
|
||||
else if (c == '\t')
|
||||
{
|
||||
outString += "\\t";
|
||||
}
|
||||
else
|
||||
{
|
||||
outString += c;
|
||||
}
|
||||
}
|
||||
else if(c == '\\') outString += "\\\\";
|
||||
else if(c == '\"') outString += "\\\"";
|
||||
else if(c == '\b') outString += "\\b";
|
||||
else if(c == '\n') outString += "\\n";
|
||||
else if(c == '\r') outString += "\\r";
|
||||
else if(c == '\t') outString += "\\t";
|
||||
else outString += c;
|
||||
|
||||
return outString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the current <see cref="Claunia.PropertyList.NSString"/> to the specified object.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSString" />.
|
||||
/// </summary>
|
||||
/// <returns>A 32-bit signed integer that indicates the lexical relationship between the two comparands.</returns>
|
||||
/// <param name="o">Object to compare to the current <see cref="Claunia.PropertyList.NSString"/>.</param>
|
||||
public int CompareTo(Object o)
|
||||
{
|
||||
if (o is NSString)
|
||||
return string.Compare(Content, ((NSString)o).Content, StringComparison.Ordinal);
|
||||
if (o is String)
|
||||
return string.Compare(Content, ((String)o), StringComparison.Ordinal);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSString"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSString"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSString"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.NSString" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.NSString" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
if (!(obj is NSString))
|
||||
return false;
|
||||
if(!(obj is NSString)) return false;
|
||||
|
||||
return content == ((NSString)obj).content;
|
||||
return Content == ((NSString)obj).Content;
|
||||
}
|
||||
|
||||
internal static bool IsASCIIEncodable(string text)
|
||||
{
|
||||
foreach(char c in text)
|
||||
if ((int)c > 0x7F)
|
||||
if(c > 0x7F)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static public explicit operator string(NSString value)
|
||||
public static explicit operator string(NSString value)
|
||||
{
|
||||
return value.content;
|
||||
return value.Content;
|
||||
}
|
||||
|
||||
static public explicit operator NSString(string value)
|
||||
public static explicit operator NSString(string value)
|
||||
{
|
||||
return new NSString(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
// 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.Runtime.Serialization;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -37,9 +37,7 @@ namespace Claunia.PropertyList
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PropertyListException" /> class.
|
||||
/// </summary>
|
||||
public PropertyListException()
|
||||
{
|
||||
}
|
||||
public PropertyListException() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PropertyListException" /> class.
|
||||
@@ -47,10 +45,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="message">
|
||||
/// The error message that explains the reason for the exception.
|
||||
/// </param>
|
||||
public PropertyListException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public PropertyListException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PropertyListException" /> class.
|
||||
@@ -62,10 +57,7 @@ namespace Claunia.PropertyList
|
||||
/// The exception that is the cause of the current exception, or <see langword="null" />
|
||||
/// if no inner exception is specified.
|
||||
/// </param>
|
||||
public PropertyListException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
public PropertyListException(string message, Exception inner) : base(message, inner) { }
|
||||
|
||||
#if !NETCORE
|
||||
protected PropertyListException(SerializationInfo info, StreamingContext context)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
// 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;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -38,9 +37,6 @@ namespace Claunia.PropertyList
|
||||
/// Creates a new exception with the given message.
|
||||
/// </summary>
|
||||
/// <param name="message">A message containing information about the nature of the exception.</param>
|
||||
public PropertyListFormatException(string message) : base(message)
|
||||
{
|
||||
public PropertyListFormatException(string message) : base(message) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,16 +22,16 @@
|
||||
// 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.Text;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// @author Daniel Dreibrodt
|
||||
@@ -51,33 +51,17 @@ namespace Claunia.PropertyList
|
||||
/// <param name="dataBeginning">The very first bytes of data of the property list (minus any whitespace) as a string</param>
|
||||
static int DetermineTypeExact(ReadOnlySpan<byte> dataBeginning)
|
||||
{
|
||||
if (dataBeginning.Length == 0)
|
||||
{
|
||||
return TYPE_ERROR_BLANK;
|
||||
}
|
||||
else if (dataBeginning[0] == '(' || dataBeginning[0] == '{' || dataBeginning[0] == '/')
|
||||
{
|
||||
return TYPE_ASCII;
|
||||
}
|
||||
else if (dataBeginning[0] == '<')
|
||||
{
|
||||
return TYPE_XML;
|
||||
}
|
||||
else if (dataBeginning.Length >= 6
|
||||
&& dataBeginning[0] == 'b'
|
||||
&& dataBeginning[1] == 'p'
|
||||
&& dataBeginning[2] == 'l'
|
||||
&& dataBeginning[3] == 'i'
|
||||
&& dataBeginning[4] == 's'
|
||||
&& dataBeginning[5] == 't')
|
||||
{
|
||||
return TYPE_BINARY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dataBeginning.Length == 0) return TYPE_ERROR_BLANK;
|
||||
|
||||
if(dataBeginning[0] == '(' || dataBeginning[0] == '{' || dataBeginning[0] == '/') return TYPE_ASCII;
|
||||
|
||||
if(dataBeginning[0] == '<') return TYPE_XML;
|
||||
if(dataBeginning.Length >= 6 && dataBeginning[0] == 'b' && dataBeginning[1] == 'p' &&
|
||||
dataBeginning[2] == 'l' && dataBeginning[3] == 'i' && dataBeginning[4] == 's' &&
|
||||
dataBeginning[5] == 't') return TYPE_BINARY;
|
||||
|
||||
return TYPE_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the type of a property list by means of the first bytes of its data
|
||||
@@ -86,22 +70,16 @@ namespace Claunia.PropertyList
|
||||
/// <param name="bytes">The type of the property list</param>
|
||||
static int DetermineType(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (bytes.Length == 0)
|
||||
return TYPE_ERROR_BLANK;
|
||||
if(bytes.Length == 0) return TYPE_ERROR_BLANK;
|
||||
|
||||
//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++;
|
||||
}
|
||||
if(bytes.Length >= 3 && (bytes[0] & 0xFF) == 0xEF && (bytes[1] & 0xFF) == 0xBB &&
|
||||
(bytes[2] & 0xFF) == 0xBF) offset += 3;
|
||||
while(offset < bytes.Length && (bytes[offset] == ' ' || bytes[offset] == '\t' || bytes[offset] == '\r' ||
|
||||
bytes[offset] == '\n' || bytes[offset] == '\f')) offset++;
|
||||
|
||||
var header = bytes.Slice(offset, Math.Min(8, bytes.Length - offset));
|
||||
ReadOnlySpan<byte> header = bytes.Slice(offset, Math.Min(8, bytes.Length - offset));
|
||||
return DetermineTypeExact(header);
|
||||
}
|
||||
|
||||
@@ -109,13 +87,14 @@ namespace Claunia.PropertyList
|
||||
/// Determines the type of a property list by means of the first bytes of its data
|
||||
/// </summary>
|
||||
/// <returns>The type of the property list</returns>
|
||||
/// <param name="fs">An input stream pointing to the beginning of the property list data.
|
||||
/// <param name="fs">
|
||||
/// An input stream pointing to the beginning of the property list data.
|
||||
/// The stream will be reset to the beginning of the property
|
||||
/// list data after the type has been determined.</param>
|
||||
/// list data after the type has been determined.
|
||||
/// </param>
|
||||
static int DetermineType(Stream fs, long offset = 0)
|
||||
{
|
||||
if (fs.Length == 0)
|
||||
return TYPE_ERROR_BLANK;
|
||||
if(fs.Length == 0) return TYPE_ERROR_BLANK;
|
||||
|
||||
long index = offset;
|
||||
long readLimit = index + 1024;
|
||||
@@ -132,15 +111,16 @@ namespace Claunia.PropertyList
|
||||
fs.Seek(mark, SeekOrigin.Begin);
|
||||
return DetermineType(fs, readLimit);
|
||||
}
|
||||
|
||||
b = fs.ReadByte();
|
||||
|
||||
//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))));
|
||||
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' || bom));
|
||||
|
||||
if(b==-1)
|
||||
return TYPE_ERROR_BLANK;
|
||||
if(b == -1) return TYPE_ERROR_BLANK;
|
||||
|
||||
byte[] magicBytes = new byte[8];
|
||||
magicBytes[0] = (byte)b;
|
||||
@@ -182,10 +162,7 @@ namespace Claunia.PropertyList
|
||||
/// <returns>The root object in the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
|
||||
public static NSObject Parse(FileInfo f)
|
||||
{
|
||||
using (FileStream fis = f.OpenRead())
|
||||
{
|
||||
return Parse(fis);
|
||||
}
|
||||
using(FileStream fis = f.OpenRead()) return Parse(fis);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -197,14 +174,12 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
switch(DetermineType(bytes))
|
||||
{
|
||||
case TYPE_BINARY:
|
||||
return BinaryPropertyListParser.Parse(bytes);
|
||||
case TYPE_XML:
|
||||
return XmlPropertyListParser.Parse(bytes);
|
||||
case TYPE_ASCII:
|
||||
return ASCIIPropertyListParser.Parse(bytes);
|
||||
case TYPE_BINARY: return BinaryPropertyListParser.Parse(bytes);
|
||||
case TYPE_XML: return XmlPropertyListParser.Parse(bytes);
|
||||
case TYPE_ASCII: return ASCIIPropertyListParser.Parse(bytes);
|
||||
default:
|
||||
throw new PropertyListFormatException("The given data is not a property list of a supported format.");
|
||||
throw new
|
||||
PropertyListFormatException("The given data is not a property list of a supported format.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,14 +204,12 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
switch(DetermineType(bytes))
|
||||
{
|
||||
case TYPE_BINARY:
|
||||
return BinaryPropertyListParser.Parse(bytes);
|
||||
case TYPE_XML:
|
||||
return XmlPropertyListParser.Parse(bytes.ToArray());
|
||||
case TYPE_ASCII:
|
||||
return ASCIIPropertyListParser.Parse(bytes);
|
||||
case TYPE_BINARY: return BinaryPropertyListParser.Parse(bytes);
|
||||
case TYPE_XML: return XmlPropertyListParser.Parse(bytes.ToArray());
|
||||
case TYPE_ASCII: return ASCIIPropertyListParser.Parse(bytes);
|
||||
default:
|
||||
throw new PropertyListFormatException("The given data is not a property list of a supported format.");
|
||||
throw new
|
||||
PropertyListFormatException("The given data is not a property list of a supported format.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,15 +232,11 @@ namespace Claunia.PropertyList
|
||||
public static void SaveAsXml(NSObject root, FileInfo outFile)
|
||||
{
|
||||
string parent = outFile.DirectoryName;
|
||||
if (!Directory.Exists(parent))
|
||||
Directory.CreateDirectory(parent);
|
||||
if(!Directory.Exists(parent)) Directory.CreateDirectory(parent);
|
||||
|
||||
// Use Create here -- to make sure that when the updated file is shorter than
|
||||
// the original file, no "obsolete" data is left at the end.
|
||||
using (Stream fous = outFile.Open(FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
SaveAsXml(root, fous);
|
||||
}
|
||||
using(Stream fous = outFile.Open(FileMode.Create, FileAccess.ReadWrite)) SaveAsXml(root, fous);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -285,10 +254,8 @@ namespace Claunia.PropertyList
|
||||
w.Write(root.ToXmlPropertyList());
|
||||
w.Close();
|
||||
#else
|
||||
using (StreamWriter w = new StreamWriter(outStream, Encoding.UTF8, bufferSize: 1024, leaveOpen: true))
|
||||
{
|
||||
using(StreamWriter w = new StreamWriter(outStream, Encoding.UTF8, 1024, true))
|
||||
w.Write(root.ToXmlPropertyList());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -312,8 +279,7 @@ namespace Claunia.PropertyList
|
||||
public static void SaveAsBinary(NSObject root, FileInfo outFile)
|
||||
{
|
||||
string parent = outFile.DirectoryName;
|
||||
if (!Directory.Exists(parent))
|
||||
Directory.CreateDirectory(parent);
|
||||
if(!Directory.Exists(parent)) Directory.CreateDirectory(parent);
|
||||
BinaryPropertyListWriter.Write(outFile, root);
|
||||
}
|
||||
|
||||
@@ -348,14 +314,11 @@ namespace Claunia.PropertyList
|
||||
public static void SaveAsASCII(NSDictionary root, FileInfo outFile)
|
||||
{
|
||||
string parent = outFile.DirectoryName;
|
||||
if (!Directory.Exists(parent))
|
||||
Directory.CreateDirectory(parent);
|
||||
if(!Directory.Exists(parent)) Directory.CreateDirectory(parent);
|
||||
using(Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
using(StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
|
||||
{
|
||||
w.Write(root.ToASCIIPropertyList());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a property list with the given object as root into a ASCII file.
|
||||
@@ -366,14 +329,11 @@ namespace Claunia.PropertyList
|
||||
public static void SaveAsASCII(NSArray root, FileInfo outFile)
|
||||
{
|
||||
string parent = outFile.DirectoryName;
|
||||
if (!Directory.Exists(parent))
|
||||
Directory.CreateDirectory(parent);
|
||||
if(!Directory.Exists(parent)) Directory.CreateDirectory(parent);
|
||||
using(Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
using(StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
|
||||
{
|
||||
w.Write(root.ToASCIIPropertyList());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a given property list file into ASCII format.
|
||||
@@ -383,19 +343,11 @@ namespace Claunia.PropertyList
|
||||
public static void ConvertToASCII(FileInfo inFile, FileInfo outFile)
|
||||
{
|
||||
NSObject root = Parse(inFile);
|
||||
if (root is NSDictionary)
|
||||
{
|
||||
SaveAsASCII((NSDictionary)root, outFile);
|
||||
}
|
||||
else if (root is NSArray)
|
||||
{
|
||||
SaveAsASCII((NSArray)root, outFile);
|
||||
}
|
||||
if(root is NSDictionary) SaveAsASCII((NSDictionary)root, outFile);
|
||||
else if(root is NSArray) SaveAsASCII((NSArray)root, outFile);
|
||||
else
|
||||
{
|
||||
throw new PropertyListFormatException("The root of the given input property list "
|
||||
+ "is neither a Dictionary nor an Array!");
|
||||
}
|
||||
throw new PropertyListFormatException("The root of the given input property list " +
|
||||
"is neither a Dictionary nor an Array!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -407,14 +359,11 @@ namespace Claunia.PropertyList
|
||||
public static void SaveAsGnuStepASCII(NSDictionary root, FileInfo outFile)
|
||||
{
|
||||
string parent = outFile.DirectoryName;
|
||||
if (!Directory.Exists(parent))
|
||||
Directory.CreateDirectory(parent);
|
||||
if(!Directory.Exists(parent)) Directory.CreateDirectory(parent);
|
||||
using(Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
using(StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
|
||||
{
|
||||
w.Write(root.ToGnuStepASCIIPropertyList());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a property list with the given object as root into a GnuStep ASCII file.
|
||||
@@ -425,14 +374,11 @@ namespace Claunia.PropertyList
|
||||
public static void SaveAsGnuStepASCII(NSArray root, FileInfo outFile)
|
||||
{
|
||||
string parent = outFile.DirectoryName;
|
||||
if (!Directory.Exists(parent))
|
||||
Directory.CreateDirectory(parent);
|
||||
if(!Directory.Exists(parent)) Directory.CreateDirectory(parent);
|
||||
using(Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
using(StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
|
||||
{
|
||||
w.Write(root.ToGnuStepASCIIPropertyList());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a given property list file into GnuStep ASCII format.
|
||||
@@ -442,20 +388,11 @@ namespace Claunia.PropertyList
|
||||
public static void ConvertToGnuStepASCII(FileInfo inFile, FileInfo outFile)
|
||||
{
|
||||
NSObject root = Parse(inFile);
|
||||
if (root is NSDictionary)
|
||||
{
|
||||
SaveAsGnuStepASCII((NSDictionary)root, outFile);
|
||||
}
|
||||
else if (root is NSArray)
|
||||
{
|
||||
SaveAsGnuStepASCII((NSArray)root, outFile);
|
||||
}
|
||||
if(root is NSDictionary) SaveAsGnuStepASCII((NSDictionary)root, outFile);
|
||||
else if(root is NSArray) SaveAsGnuStepASCII((NSArray)root, outFile);
|
||||
else
|
||||
{
|
||||
throw new PropertyListFormatException("The root of the given input property list "
|
||||
+ "is neither a Dictionary nor an Array!");
|
||||
throw new PropertyListFormatException("The root of the given input property list " +
|
||||
"is neither a Dictionary nor an Array!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
150
plist-cil/UID.cs
150
plist-cil/UID.cs
@@ -22,6 +22,7 @@
|
||||
// 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.Buffers.Binary;
|
||||
using System.Text;
|
||||
@@ -43,11 +44,12 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="bytes">Bytes.</param>
|
||||
[Obsolete("UIDs have not meaningful names")]
|
||||
public UID(String name, ReadOnlySpan<byte> bytes)
|
||||
public UID(string name, ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if(bytes.Length != 1 && bytes.Length != 2 && bytes.Length != 4 && bytes.Length != 8)
|
||||
throw new ArgumentException("Type argument is not valid.");
|
||||
this.value = (ulong)BinaryPropertyListParser.ParseLong(bytes);
|
||||
|
||||
value = (ulong)BinaryPropertyListParser.ParseLong(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,7 +60,8 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
if(bytes.Length != 1 && bytes.Length != 2 && bytes.Length != 4 && bytes.Length != 8)
|
||||
throw new ArgumentException("Type argument is not valid.");
|
||||
this.value = (ulong)BinaryPropertyListParser.ParseLong(bytes);
|
||||
|
||||
value = (ulong)BinaryPropertyListParser.ParseLong(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,9 +70,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Unsigned 8-bit number.</param>
|
||||
[Obsolete("UIDs have no meaningful names")]
|
||||
public UID(String name, byte number)
|
||||
public UID(string name, byte number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +81,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="number">Unsigned 8-bit number.</param>
|
||||
public UID(byte number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,9 +90,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Unsigned 8-bit number.</param>
|
||||
[Obsolete("UIDs must be unsigned values")]
|
||||
public UID(String name, sbyte number)
|
||||
public UID(string name, sbyte number)
|
||||
{
|
||||
this.value = (ulong)number;
|
||||
value = (ulong)number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -98,9 +101,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Unsigned 16-bit number.</param>
|
||||
[Obsolete("UIDs have no meaningful names")]
|
||||
public UID(String name, ushort number)
|
||||
public UID(string name, ushort number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -110,7 +113,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="number">Unsigned 16-bit number.</param>
|
||||
public UID(ushort number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,9 +122,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Signed 16-bit number.</param>
|
||||
[Obsolete("UIDs must be unsigned values")]
|
||||
public UID(String name, short number)
|
||||
public UID(string name, short number)
|
||||
{
|
||||
this.value = (ulong)number;
|
||||
value = (ulong)number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -130,9 +133,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Unsigned 32-bit number.</param>
|
||||
[Obsolete("UIDs have no meaningful names")]
|
||||
public UID(String name, uint number)
|
||||
public UID(string name, uint number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -141,7 +144,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="number">Unsigned 32-bit number.</param>
|
||||
public UID(uint number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -150,9 +153,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Signed 32-bit number.</param>
|
||||
[Obsolete("UIDs must be unsigned values")]
|
||||
public UID(String name, int number)
|
||||
public UID(string name, int number)
|
||||
{
|
||||
this.value = (ulong)number;
|
||||
value = (ulong)number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -161,9 +164,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Unsigned 64-bit number.</param>
|
||||
[Obsolete("UIDs have no meaningful names")]
|
||||
public UID(String name, ulong number)
|
||||
public UID(string name, ulong number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,7 +175,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="number">Unsigned 64-bit number.</param>
|
||||
public UID(ulong number)
|
||||
{
|
||||
this.value = number;
|
||||
value = number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -181,9 +184,9 @@ namespace Claunia.PropertyList
|
||||
/// <param name="name">Name.</param>
|
||||
/// <param name="number">Signed 64-bit number.</param>
|
||||
[Obsolete("UIDs must be unsigned values")]
|
||||
public UID(String name, long number)
|
||||
public UID(string name, long number)
|
||||
{
|
||||
this.value = (ulong)number;
|
||||
value = (ulong)number;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -194,8 +197,8 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] bytes = new byte[this.ByteCount];
|
||||
this.GetBytes(bytes);
|
||||
byte[] bytes = new byte[ByteCount];
|
||||
GetBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -207,24 +210,21 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.value <= byte.MaxValue)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (this.value <= ushort.MaxValue)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if (this.value <= uint.MaxValue)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(value <= byte.MaxValue) return 1;
|
||||
|
||||
if(value <= ushort.MaxValue) return 2;
|
||||
if(value <= uint.MaxValue) return 4;
|
||||
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[Obsolete("UIDs have no meaningful names")]
|
||||
public string Name => value.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the bytes required to represent this <see cref="UID" /> to a byte span.
|
||||
@@ -234,39 +234,25 @@ namespace Claunia.PropertyList
|
||||
/// </param>
|
||||
public void GetBytes(Span<byte> bytes)
|
||||
{
|
||||
switch (this.ByteCount)
|
||||
switch(ByteCount)
|
||||
{
|
||||
case 1:
|
||||
bytes[0] = (byte)this.value;
|
||||
bytes[0] = (byte)value;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
BinaryPrimitives.WriteUInt16BigEndian(bytes, (ushort)this.value);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(bytes, (ushort)value);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
BinaryPrimitives.WriteUInt32BigEndian(bytes, (uint)this.value);
|
||||
BinaryPrimitives.WriteUInt32BigEndian(bytes, (uint)value);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
BinaryPrimitives.WriteUInt64BigEndian(bytes, this.value);
|
||||
BinaryPrimitives.WriteUInt64BigEndian(bytes, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[Obsolete("UIDs have no meaningful names")]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.value.ToString();
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,18 +266,17 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(xml, level);
|
||||
xml.Append("<string>");
|
||||
Span<byte> bytes = stackalloc byte[this.ByteCount];
|
||||
this.GetBytes(bytes);
|
||||
foreach (byte b in bytes)
|
||||
xml.Append(String.Format("{0:x2}", b));
|
||||
Span<byte> bytes = stackalloc byte[ByteCount];
|
||||
GetBytes(bytes);
|
||||
foreach(byte b in bytes) xml.Append(string.Format("{0:x2}", b));
|
||||
xml.Append("</string>");
|
||||
}
|
||||
|
||||
internal override void ToBinary(BinaryPropertyListWriter outPlist)
|
||||
{
|
||||
outPlist.Write(0x80 + this.ByteCount - 1);
|
||||
Span<byte> bytes = stackalloc byte[this.ByteCount];
|
||||
this.GetBytes(bytes);
|
||||
outPlist.Write(0x80 + ByteCount - 1);
|
||||
Span<byte> bytes = stackalloc byte[ByteCount];
|
||||
GetBytes(bytes);
|
||||
outPlist.Write(bytes);
|
||||
}
|
||||
|
||||
@@ -299,10 +284,9 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
Indent(ascii, level);
|
||||
ascii.Append("\"");
|
||||
Span<byte> bytes = stackalloc byte[this.ByteCount];
|
||||
this.GetBytes(bytes);
|
||||
foreach (byte b in bytes)
|
||||
ascii.Append(String.Format("{0:x2}", b));
|
||||
Span<byte> bytes = stackalloc byte[ByteCount];
|
||||
GetBytes(bytes);
|
||||
foreach(byte b in bytes) ascii.Append(string.Format("{0:x2}", b));
|
||||
ascii.Append("\"");
|
||||
}
|
||||
|
||||
@@ -312,11 +296,17 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.UID"/>.
|
||||
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.UID" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.UID"/>.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.UID"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="Claunia.PropertyList.NSObject" /> to compare with the current
|
||||
/// <see cref="Claunia.PropertyList.UID" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject" /> is equal to the current
|
||||
/// <see cref="Claunia.PropertyList.UID" />; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(NSObject obj)
|
||||
{
|
||||
return Equals((object)obj);
|
||||
@@ -325,10 +315,9 @@ namespace Claunia.PropertyList
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var uid = obj as UID;
|
||||
UID uid = obj as UID;
|
||||
|
||||
if (uid == null)
|
||||
return false;
|
||||
if(uid == null) return false;
|
||||
|
||||
return uid.value == value;
|
||||
}
|
||||
@@ -336,14 +325,13 @@ namespace Claunia.PropertyList
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.value.GetHashCode();
|
||||
return value.GetHashCode();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.value} (UID)";
|
||||
return $"{value} (UID)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
// 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.Xml;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
|
||||
namespace Claunia.PropertyList
|
||||
{
|
||||
@@ -45,13 +46,11 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
|
||||
var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore };
|
||||
XmlReaderSettings settings = new XmlReaderSettings {DtdProcessing = DtdProcessing.Ignore};
|
||||
|
||||
using(Stream stream = f.OpenRead())
|
||||
using(XmlReader reader = XmlReader.Create(stream, settings))
|
||||
{
|
||||
doc.Load(reader);
|
||||
}
|
||||
|
||||
return ParseDocument(doc);
|
||||
}
|
||||
@@ -79,10 +78,7 @@ namespace Claunia.PropertyList
|
||||
XmlReaderSettings settings = new XmlReaderSettings();
|
||||
settings.DtdProcessing = DtdProcessing.Ignore;
|
||||
|
||||
using (XmlReader reader = XmlReader.Create(str, settings))
|
||||
{
|
||||
doc.Load(reader);
|
||||
}
|
||||
using(XmlReader reader = XmlReader.Create(str, settings)) doc.Load(reader);
|
||||
|
||||
return ParseDocument(doc);
|
||||
}
|
||||
@@ -111,21 +107,16 @@ namespace Claunia.PropertyList
|
||||
/// <param name="doc">The XML document.</param>
|
||||
static NSObject ParseDocument(XmlDocument doc)
|
||||
{
|
||||
var docType = doc.ChildNodes
|
||||
.OfType<XmlNode>()
|
||||
XmlNode docType = doc.ChildNodes.OfType<XmlNode>()
|
||||
.SingleOrDefault(n => n.NodeType == XmlNodeType.DocumentType);
|
||||
|
||||
if(docType == null)
|
||||
{
|
||||
if(!doc.DocumentElement.Name.Equals("plist"))
|
||||
{
|
||||
throw new XmlException("The given XML document is not a property list.");
|
||||
}
|
||||
}
|
||||
else if(!docType.Name.Equals("plist"))
|
||||
{
|
||||
throw new XmlException("The given XML document is not a property list.");
|
||||
}
|
||||
|
||||
XmlNode rootNode;
|
||||
|
||||
@@ -135,10 +126,10 @@ namespace Claunia.PropertyList
|
||||
List<XmlNode> rootNodes = FilterElementNodes(doc.DocumentElement.ChildNodes);
|
||||
if(rootNodes.Count == 0)
|
||||
throw new PropertyListFormatException("The given XML property list has no root element!");
|
||||
if (rootNodes.Count == 1)
|
||||
rootNode = rootNodes[0];
|
||||
if(rootNodes.Count == 1) rootNode = rootNodes[0];
|
||||
else
|
||||
throw new PropertyListFormatException("The given XML property list has more than one root element!");
|
||||
throw
|
||||
new PropertyListFormatException("The given XML property list has more than one root element!");
|
||||
}
|
||||
else
|
||||
//Root NSObject not wrapped in plist-tag
|
||||
@@ -167,30 +158,25 @@ namespace Claunia.PropertyList
|
||||
|
||||
dict.Add(keyString, ParseObject(val));
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
if(n.Name.Equals("array"))
|
||||
{
|
||||
List<XmlNode> children = FilterElementNodes(n.ChildNodes);
|
||||
NSArray array = new NSArray(children.Count);
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
{
|
||||
array.Add(ParseObject(children[i]));
|
||||
}
|
||||
for(int i = 0; i < children.Count; i++) array.Add(ParseObject(children[i]));
|
||||
return array;
|
||||
}
|
||||
if (n.Name.Equals("true"))
|
||||
return new NSNumber(true);
|
||||
if (n.Name.Equals("false"))
|
||||
return new NSNumber(false);
|
||||
if (n.Name.Equals("integer"))
|
||||
return new NSNumber(GetNodeTextContents(n), NSNumber.INTEGER);
|
||||
if (n.Name.Equals("real"))
|
||||
return new NSNumber(GetNodeTextContents(n), NSNumber.REAL);
|
||||
if (n.Name.Equals("string"))
|
||||
return new NSString(GetNodeTextContents(n));
|
||||
if (n.Name.Equals("data"))
|
||||
return new NSData(GetNodeTextContents(n));
|
||||
|
||||
if(n.Name.Equals("true")) return new NSNumber(true);
|
||||
if(n.Name.Equals("false")) return new NSNumber(false);
|
||||
if(n.Name.Equals("integer")) return new NSNumber(GetNodeTextContents(n), NSNumber.INTEGER);
|
||||
if(n.Name.Equals("real")) return new NSNumber(GetNodeTextContents(n), NSNumber.REAL);
|
||||
if(n.Name.Equals("string")) return new NSString(GetNodeTextContents(n));
|
||||
if(n.Name.Equals("data")) return new NSData(GetNodeTextContents(n));
|
||||
|
||||
return n.Name.Equals("date") ? new NSDate(GetNodeTextContents(n)) : null;
|
||||
}
|
||||
|
||||
@@ -222,23 +208,23 @@ namespace Claunia.PropertyList
|
||||
string content = n.Value; //This concatenates any adjacent text/cdata/entity nodes
|
||||
return content ?? "";
|
||||
}
|
||||
|
||||
if(n.HasChildNodes)
|
||||
{
|
||||
XmlNodeList children = n.ChildNodes;
|
||||
|
||||
foreach(XmlNode child in children)
|
||||
{
|
||||
//Skip any non-text nodes, like comments or entities
|
||||
if(child.NodeType == XmlNodeType.Text || child.NodeType == XmlNodeType.CDATA)
|
||||
{
|
||||
string content = child.Value; //This concatenates any adjacent text/cdata/entity nodes
|
||||
return content ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user