diff --git a/plist-cil.benchmark/BinaryPropertyListParserBenchmarks.cs b/plist-cil.benchmark/BinaryPropertyListParserBenchmarks.cs index 2db8fc2..2885af7 100644 --- a/plist-cil.benchmark/BinaryPropertyListParserBenchmarks.cs +++ b/plist-cil.benchmark/BinaryPropertyListParserBenchmarks.cs @@ -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,8 +19,8 @@ namespace Claunia.PropertyList.Benchmark [Benchmark] public NSObject ReadLargePropertylistTest() { - var nsObject = PropertyListParser.Parse(this.data); + NSObject nsObject = PropertyListParser.Parse(data); return nsObject; } } -} +} \ No newline at end of file diff --git a/plist-cil.benchmark/BinaryPropertyListWriterBenchmarks.cs b/plist-cil.benchmark/BinaryPropertyListWriterBenchmarks.cs index a461b12..f40b807 100644 --- a/plist-cil.benchmark/BinaryPropertyListWriterBenchmarks.cs +++ b/plist-cil.benchmark/BinaryPropertyListWriterBenchmarks.cs @@ -7,7 +7,7 @@ namespace Claunia.PropertyList.Benchmark [MemoryDiagnoser] public class BinaryPropertyListWriterBenchmarks { - private NSObject data = null; + NSObject data; [GlobalSetup] public void Setup() @@ -15,11 +15,10 @@ namespace Claunia.PropertyList.Benchmark data = PropertyListParser.Parse("plist.bin"); } - [Benchmark] public byte[] WriteLargePropertylistTest() { return BinaryPropertyListWriter.WriteToArray(data); } } -} +} \ No newline at end of file diff --git a/plist-cil.benchmark/Program.cs b/plist-cil.benchmark/Program.cs index 040c0ee..3d39789 100644 --- a/plist-cil.benchmark/Program.cs +++ b/plist-cil.benchmark/Program.cs @@ -1,5 +1,5 @@ -using BenchmarkDotNet.Running; -using System; +using BenchmarkDotNet.Reports; +using BenchmarkDotNet.Running; namespace Claunia.PropertyList.Benchmark { @@ -7,8 +7,8 @@ namespace Claunia.PropertyList.Benchmark { static void Main(string[] args) { - var summary = BenchmarkRunner.Run(); + Summary summary = BenchmarkRunner.Run(); summary = BenchmarkRunner.Run(); } } -} +} \ No newline at end of file diff --git a/plist-cil.test/BinaryPropertyListParserTests.cs b/plist-cil.test/BinaryPropertyListParserTests.cs index 863ad66..daafbbf 100644 --- a/plist-cil.test/BinaryPropertyListParserTests.cs +++ b/plist-cil.test/BinaryPropertyListParserTests.cs @@ -6,31 +6,31 @@ namespace plistcil.test public class BinaryPropertyListParserTests { [Theory] - [InlineData(new byte[] { 0x08 }, 0x08)] - [InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 }, 7)] - [InlineData(new byte[] { 0x00, 0x0e, 0x47, 0x7b }, 0x00000000000e477b)] + [InlineData(new byte[] {0x08}, 0x08)] + [InlineData(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, 7)] + [InlineData(new byte[] {0x00, 0x0e, 0x47, 0x7b}, 0x00000000000e477b)] public void ParseUnsignedIntTest(byte[] binaryValue, int expectedValue) { Assert.Equal(expectedValue, BinaryPropertyListParser.ParseUnsignedInt(binaryValue)); } [Theory] - [InlineData(new byte[] { 0x57 }, 0x57)] - [InlineData(new byte[] { 0x40, 0x2d, 0xf8, 0x4d }, 0x402df84d)] - [InlineData(new byte[] { 0x41, 0xb4, 0x83, 0x98, 0x2a, 0x00, 0x00, 0x00 }, 0x41b483982a000000)] - [InlineData(new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x19 }, unchecked((long)0xfffffffffffffc19))] + [InlineData(new byte[] {0x57}, 0x57)] + [InlineData(new byte[] {0x40, 0x2d, 0xf8, 0x4d}, 0x402df84d)] + [InlineData(new byte[] {0x41, 0xb4, 0x83, 0x98, 0x2a, 0x00, 0x00, 0x00}, 0x41b483982a000000)] + [InlineData(new byte[] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x19}, unchecked((long)0xfffffffffffffc19))] public void ParseLongTest(byte[] binaryValue, long expectedValue) { Assert.Equal(expectedValue, BinaryPropertyListParser.ParseLong(binaryValue)); } [Theory] - [InlineData(new byte[] { 0x41, 0xb4, 0x83, 0x98, 0x2a, 0x00, 0x00, 0x00 }, 344168490)] - [InlineData(new byte[] { 0x40, 0x09, 0x21, 0xf9, 0xf0, 0x1b, 0x86, 0x6e }, 3.14159)] - [InlineData(new byte[] { 0x40, 0x2d, 0xf8, 0x4d }, 2.71828007698059)] + [InlineData(new byte[] {0x41, 0xb4, 0x83, 0x98, 0x2a, 0x00, 0x00, 0x00}, 344168490)] + [InlineData(new byte[] {0x40, 0x09, 0x21, 0xf9, 0xf0, 0x1b, 0x86, 0x6e}, 3.14159)] + [InlineData(new byte[] {0x40, 0x2d, 0xf8, 0x4d}, 2.71828007698059)] public void ParseDoubleTest(byte[] binaryValue, double expectedValue) { Assert.Equal(expectedValue, BinaryPropertyListParser.ParseDouble(binaryValue), 14); } } -} +} \ No newline at end of file diff --git a/plist-cil.test/BinaryPropertyListWriterTests.cs b/plist-cil.test/BinaryPropertyListWriterTests.cs index 22d54ac..2cebf9e 100644 --- a/plist-cil.test/BinaryPropertyListWriterTests.cs +++ b/plist-cil.test/BinaryPropertyListWriterTests.cs @@ -1,73 +1,73 @@ -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() { - byte[] data = File.ReadAllBytes("test-files/plist2.bin"); + byte[] data = File.ReadAllBytes("test-files/plist2.bin"); NSObject root = PropertyListParser.Parse(data); - using (MemoryStream actualOutput = new MemoryStream()) - using (Stream expectedOutput = File.OpenRead("test-files/plist2.bin")) - using (ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput)) - { - BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream); - writer.ReuseObjectIds = false; - writer.Write(root); - } + using(MemoryStream actualOutput = new MemoryStream()) + using(Stream expectedOutput = File.OpenRead("test-files/plist2.bin")) + using(ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput)) + { + BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream); + writer.ReuseObjectIds = false; + writer.Write(root); + } } [Fact] public void Roundtrip3Test() { - byte[] data = File.ReadAllBytes("test-files/plist3.bin"); + byte[] data = File.ReadAllBytes("test-files/plist3.bin"); NSObject root = PropertyListParser.Parse(data); - using (MemoryStream actualOutput = new MemoryStream()) - using (Stream expectedOutput = File.OpenRead("test-files/plist3.bin")) - using (ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput)) - { - BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream); - writer.ReuseObjectIds = false; - writer.Write(root); - } + using(MemoryStream actualOutput = new MemoryStream()) + using(Stream expectedOutput = File.OpenRead("test-files/plist3.bin")) + using(ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput)) + { + BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream); + writer.ReuseObjectIds = false; + writer.Write(root); + } } [Fact] public void Roundtrip4Test() { - byte[] data = File.ReadAllBytes("test-files/plist4.bin"); + byte[] data = File.ReadAllBytes("test-files/plist4.bin"); NSObject root = PropertyListParser.Parse(data); - using (MemoryStream actualOutput = new MemoryStream()) - using (Stream expectedOutput = File.OpenRead("test-files/plist4.bin")) - using (ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput)) - { - BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream); - writer.ReuseObjectIds = false; - writer.Write(root); - } + using(MemoryStream actualOutput = new MemoryStream()) + using(Stream expectedOutput = File.OpenRead("test-files/plist4.bin")) + using(ValidatingStream validatingStream = new ValidatingStream(actualOutput, expectedOutput)) + { + BinaryPropertyListWriter writer = new BinaryPropertyListWriter(validatingStream); + writer.ReuseObjectIds = false; + 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); + } } } -} +} \ No newline at end of file diff --git a/plist-cil.test/IssueTest.cs b/plist-cil.test/IssueTest.cs index 49b02b4..df52f1b 100644 --- a/plist-cil.test/IssueTest.cs +++ b/plist-cil.test/IssueTest.cs @@ -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 { + /// + /// 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). + /// [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); + } + + /// + /// Makes sure that binary data is line-wrapped correctly when being serialized, in a scenario + /// where the binary data is indented. + /// + [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(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); - } - - /// - /// 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). - /// - [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); - } - - /// - /// Makes sure that binary data is line-wrapped correctly when being serialized, in a scenario - /// where the binary data is indented. - /// - [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); - } } -} - +} \ No newline at end of file diff --git a/plist-cil.test/NSArrayTests.cs b/plist-cil.test/NSArrayTests.cs index 01186fb..6c62edf 100644 --- a/plist-cil.test/NSArrayTests.cs +++ b/plist-cil.test/NSArrayTests.cs @@ -1,17 +1,13 @@ -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 { public class NSArrayTests { /// - /// Tests the addition of a .NET object to the NSArray + /// Tests the addition of a .NET object to the NSArray /// [Fact] public void AddAndContainsObjectTest() @@ -24,7 +20,30 @@ namespace plistcil.test } /// - /// Tests the method for .NET objects. + /// Tests the method. + /// + [Fact] + public void EnumeratorTest() + { + NSArray array = new NSArray(); + array.Add(0); + array.Add(1); + + IEnumerator 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()); + } + + /// + /// Tests the method for .NET objects. /// [Fact] public void IndexOfTest() @@ -38,8 +57,8 @@ namespace plistcil.test } /// - /// Tests the method for a - /// .NET object. + /// Tests the method for a + /// .NET object. /// [Fact] public void InsertTest() @@ -51,12 +70,12 @@ namespace plistcil.test array.Insert(1, "test"); - Assert.Equal(4, array.Count); + Assert.Equal(4, array.Count); Assert.Equal("test", array[1].ToObject()); } /// - /// Tests the method for a .NET object. + /// Tests the method for a .NET object. /// [Fact] public void RemoveTest() @@ -68,28 +87,5 @@ namespace plistcil.test Assert.Empty(array); } - - /// - /// Tests the method. - /// - [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()); - } } -} +} \ No newline at end of file diff --git a/plist-cil.test/NSDateTests.cs b/plist-cil.test/NSDateTests.cs index 58ddbc8..10df415 100644 --- a/plist-cil.test/NSDateTests.cs +++ b/plist-cil.test/NSDateTests.cs @@ -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,19 +9,19 @@ 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); } } -} +} \ No newline at end of file diff --git a/plist-cil.test/NSNumberTests.cs b/plist-cil.test/NSNumberTests.cs index d5672ba..28ba3f3 100644 --- a/plist-cil.test/NSNumberTests.cs +++ b/plist-cil.test/NSNumberTests.cs @@ -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,15 +8,15 @@ 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()); + Assert.Equal(10032936613, number.ToObject()); } [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()); } @@ -33,12 +26,12 @@ namespace plistcil.test // TimeZoneOffsetFromUTC // 7200.000000 -#if !NETCORE + #if !NETCORE [Fact] [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: // TimeZoneOffsetFromUTC // 7200.000000 - 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: // TimeZoneOffsetFromUTC // 7200.000000 - 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,10 +67,10 @@ namespace plistcil.test // As seen in a real property list: // TimeZoneOffsetFromUTC // 7200.000000 - 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()); } -#endif + #endif } -} +} \ No newline at end of file diff --git a/plist-cil.test/ParseTest.cs b/plist-cil.test/ParseTest.cs index bff55ea..3efdb6c 100644 --- a/plist-cil.test/ParseTest.cs +++ b/plist-cil.test/ParseTest.cs @@ -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))); + return true; + } - // 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)); - } - - /** - * 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; } /** @@ -107,18 +77,18 @@ namespace plistcil.test [Fact] public static void TestASCII() { - NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1-ascii.plist")); + NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1-ascii.plist")); NSDictionary d = (NSDictionary)x; Assert.True(d.Count == 5); - Assert.Equal("valueA", ((NSString)d.ObjectForKey("keyA")).ToString()); + 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,31 +98,22 @@ 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] public static void TestASCIIWriting() { - FileInfo inf = new FileInfo("test-files/test1.plist"); - FileInfo outf = new FileInfo("test-files/out-test1-ascii.plist"); - FileInfo in2 = new FileInfo("test-files/test1-ascii.plist"); - NSDictionary x = (NSDictionary)PropertyListParser.Parse(inf); + FileInfo inf = new FileInfo("test-files/test1.plist"); + FileInfo outf = new FileInfo("test-files/out-test1-ascii.plist"); + FileInfo in2 = new FileInfo("test-files/test1-ascii.plist"); + NSDictionary x = (NSDictionary)PropertyListParser.Parse(inf); PropertyListParser.SaveAsASCII(x, outf); //Information gets lost when saving into the ASCII format (NSNumbers are converted to NSStrings) @@ -162,12 +123,46 @@ 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() { - FileInfo inf = new FileInfo("test-files/test1.plist"); - FileInfo outf = new FileInfo("test-files/out-test1-ascii-gnustep.plist"); - NSDictionary x = (NSDictionary)PropertyListParser.Parse(inf); + FileInfo inf = new FileInfo("test-files/test1.plist"); + FileInfo outf = new FileInfo("test-files/out-test1-ascii-gnustep.plist"); + NSDictionary x = (NSDictionary)PropertyListParser.Parse(inf); PropertyListParser.SaveAsGnuStepASCII(x, outf); NSObject y = PropertyListParser.Parse(outf); Assert.True(x.Equals(y)); @@ -176,86 +171,85 @@ namespace plistcil.test [Fact] public static void TestWrap() { - bool bl = true; - byte byt = 24; - short shrt = 12; - int i = 42; - long lng = 30000000000L; - float flt = 124.3f; - 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 list = new List(array); + bool bl = true; + byte byt = 24; + short shrt = 12; + int i = 42; + long lng = 30000000000L; + float flt = 124.3f; + double dbl = 32.0; + DateTime date = new DateTime(); + string strg = "Hello World"; + 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 list = new List(array); - Dictionary map = new Dictionary(); - map.Add("int", i); + Dictionary map = new Dictionary(); + 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); + Assert.True(((NSNumber)dict.ObjectForKey("int")).ToLong() == i); Assert.True(((NSNumber)dict.ObjectForKey("long")).ToLong() == lng); Assert.True(((NSDate)dict.ObjectForKey("date")).Date.Equals(date)); @@ -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)); } - -} -} - + } +} \ No newline at end of file diff --git a/plist-cil.test/PropertyListParserTests.cs b/plist-cil.test/PropertyListParserTests.cs index 1ab8b79..9a5de84 100644 --- a/plist-cil.test/PropertyListParserTests.cs +++ b/plist-cil.test/PropertyListParserTests.cs @@ -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(() => ParseEmptyStreamTestDelegate()); } - - static void ParseEmptyStreamTestDelegate() - { - using (MemoryStream stream = new MemoryStream()) - { - PropertyListParser.Parse(stream); - } - } } -} +} \ No newline at end of file diff --git a/plist-cil.test/UIDTests.cs b/plist-cil.test/UIDTests.cs index 43441ec..a9e6bcd 100644 --- a/plist-cil.test/UIDTests.cs +++ b/plist-cil.test/UIDTests.cs @@ -1,103 +1,103 @@ -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 })] - [InlineData(new byte[] { 0xAB, 0xCD, 0xEF, 0xFE })] - [InlineData(new byte[] { 0xAB, 0xCD, 0xEF, 0xFE, 0xFE, 0xEF, 0xCD, 0xAB })] + [InlineData(new byte[] {0xAB})] + [InlineData(new byte[] {0xAB, 0xCD})] + [InlineData(new byte[] {0xAB, 0xCD, 0xEF, 0xFE})] + [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()) + 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()); } } -} +} \ No newline at end of file diff --git a/plist-cil.test/UseCultureAttribute.cs b/plist-cil.test/UseCultureAttribute.cs index 4736b3e..24166a0 100644 --- a/plist-cil.test/UseCultureAttribute.cs +++ b/plist-cil.test/UseCultureAttribute.cs @@ -1,16 +1,15 @@ using System; using System.Globalization; -using System.Linq; using System.Reflection; using System.Threading; using Xunit.Sdk; /// -/// Apply this attribute to your test method to replace the -/// and -/// with another culture. +/// Apply this attribute to your test method to replace the +/// and +/// with another culture. /// -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class UseCultureAttribute : BeforeAfterTestAttribute { readonly Lazy culture; @@ -20,77 +19,76 @@ public class UseCultureAttribute : BeforeAfterTestAttribute CultureInfo originalUICulture; /// - /// Replaces the culture and UI culture of the current thread with - /// + /// Replaces the culture and UI culture of the current thread with + /// /// /// The name of the culture. /// - /// - /// This constructor overload uses for both - /// and . - /// + /// + /// This constructor overload uses for both + /// and . + /// /// - public UseCultureAttribute(string culture) - : this(culture, culture) { } + public UseCultureAttribute(string culture) : this(culture, culture) { } /// - /// Replaces the culture and UI culture of the current thread with - /// and + /// Replaces the culture and UI culture of the current thread with + /// and /// /// The name of the culture. /// The name of the UI culture. public UseCultureAttribute(string culture, string uiCulture) { - this.culture = new Lazy(() => new CultureInfo(culture)); + this.culture = new Lazy(() => new CultureInfo(culture)); this.uiCulture = new Lazy(() => new CultureInfo(uiCulture)); } /// - /// Gets the culture. + /// Gets the culture. /// - public CultureInfo Culture { get { return culture.Value; } } + public CultureInfo Culture => culture.Value; /// - /// Gets the UI culture. + /// Gets the UI culture. /// - public CultureInfo UICulture { get { return uiCulture.Value; } } + public CultureInfo UICulture => uiCulture.Value; /// - /// Stores the current - /// and - /// and replaces them with the new cultures defined in the constructor. + /// Stores the current + /// and + /// and replaces them with the new cultures defined in the constructor. /// /// The method under test public override void Before(MethodInfo methodUnderTest) { -#if NETCORE + #if NETCORE originalCulture = CultureInfo.CurrentCulture; originalUICulture = CultureInfo.CurrentUICulture; CultureInfo.CurrentCulture = Culture; CultureInfo.CurrentUICulture = Culture; #else - originalCulture = Thread.CurrentThread.CurrentCulture; + originalCulture = Thread.CurrentThread.CurrentCulture; originalUICulture = Thread.CurrentThread.CurrentUICulture; - Thread.CurrentThread.CurrentCulture = Culture; + Thread.CurrentThread.CurrentCulture = Culture; Thread.CurrentThread.CurrentUICulture = UICulture; -#endif + #endif } /// - /// Restores the original and - /// to + /// Restores the original and + /// to /// /// The method under test public override void After(MethodInfo methodUnderTest) { -#if NETCORE + #if NETCORE CultureInfo.CurrentCulture = originalCulture; CultureInfo.CurrentUICulture = originalUICulture; #else - Thread.CurrentThread.CurrentCulture = originalCulture; + Thread.CurrentThread.CurrentCulture = originalCulture; Thread.CurrentThread.CurrentUICulture = originalUICulture; -#endif + #endif } } \ No newline at end of file diff --git a/plist-cil.test/ValidatingStream.cs b/plist-cil.test/ValidatingStream.cs index a311328..a2f817d 100644 --- a/plist-cil.test/ValidatingStream.cs +++ b/plist-cil.test/ValidatingStream.cs @@ -3,10 +3,8 @@ // using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -14,113 +12,101 @@ using Xunit; namespace plistcil.test { /// - /// A which writes its output to a and validates that the data which - /// is being written to the output stream matches the data in a reference stream. + /// A which writes its output to a and validates that the data which + /// is being written to the output stream matches the data in a reference stream. /// - internal class ValidatingStream : Stream + class ValidatingStream : Stream { - private Stream output; - private Stream expectedOutput; + Stream expectedOutput; + Stream output; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// - /// The to which to write data. + /// The to which to write data. /// /// - /// The reference stream for . + /// The reference stream for . /// public ValidatingStream(Stream output, Stream expectedOutput) { - this.output = output ?? throw new ArgumentNullException(nameof(output)); + this.output = output ?? throw new ArgumentNullException(nameof(output)); this.expectedOutput = expectedOutput ?? throw new ArgumentNullException(nameof(expectedOutput)); } - /// - public override bool CanRead - { - get { return false; } - } + /// + public override bool CanRead => false; - /// - public override bool CanSeek - { - get { return false; } - } + /// + public override bool CanSeek => false; - /// - public override bool CanWrite - { - get { return true; } - } + /// + public override bool CanWrite => true; - /// - public override long Length - { - get { return this.output.Length; } - } + /// + public override long Length => output.Length; - /// + /// public override long Position { - get { return this.output.Position; } - set { throw new NotImplementedException(); } + get => output.Position; + set => throw new NotImplementedException(); } - /// + /// public override void Flush() { - this.output.Flush(); + output.Flush(); } - /// + /// public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } - /// + /// public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { throw new NotSupportedException(); } - /// + /// public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } - /// + /// public override void SetLength(long value) { throw new NotImplementedException(); } - /// + /// 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[] bufferChunk = buffer.Skip(offset).Take(count).ToArray(); byte[] expectedChunk = expected.Skip(offset).Take(count).ToArray(); // Make sure the data being writen matches the data which was written to the expected stream. // 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); } - /// + /// 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[] bufferChunk = buffer.Skip(offset).Take(count).ToArray(); byte[] expectedChunk = expected.Skip(offset).Take(count).ToArray(); // Make sure the data being writen matches the data which was written to the expected stream. @@ -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); } } -} +} \ No newline at end of file diff --git a/plist-cil/ASCIIPropertyListParser.cs b/plist-cil/ASCIIPropertyListParser.cs index bd5031d..8e643d0 100644 --- a/plist-cil/ASCIIPropertyListParser.cs +++ b/plist-cil/ASCIIPropertyListParser.cs @@ -22,252 +22,174 @@ // 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 { /// - /// - /// Parser for ASCII property lists. Supports Apple OS X/iOS and GnuStep/NeXTSTEP format. - /// This parser is based on the recursive descent paradigm, but the underlying grammar - /// is not explicitely defined. - /// - /// - /// Resources on ASCII property list format: - /// - /// - /// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html - /// - /// - /// Property List Programming Guide - Old-Style ASCII Property Lists - /// - /// - /// http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html - /// - /// - /// GnuStep - NSPropertyListSerialization class documentation - /// + /// + /// Parser for ASCII property lists. Supports Apple OS X/iOS and GnuStep/NeXTSTEP format. + /// This parser is based on the recursive descent paradigm, but the underlying grammar + /// is not explicitely defined. + /// + /// + /// Resources on ASCII property list format: + /// + /// + /// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html + /// + /// + /// Property List Programming Guide - Old-Style ASCII Property Lists + /// + /// + /// http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html + /// + /// + /// GnuStep - NSPropertyListSerialization class documentation + /// /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public class ASCIIPropertyListParser { /// - /// Parses an ASCII property list file. - /// - /// The ASCII property list file.. - /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. - /// When an error occurs during parsing. - /// When an error occured while reading from the input stream. - public static NSObject Parse(FileInfo f) - { - return Parse(f.OpenRead()); - } - - /// - /// Parses an ASCII property list from an input stream. - /// - /// The input stream that points to the property list's data. - /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. - /// When an error occurs during parsing. - /// - 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); - } - - /// - /// Parses an ASCII property list from a byte array. - /// - /// The ASCII property list data. - /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. - /// When an error occurs during parsing. - public static NSObject Parse(byte[] bytes) - { - return Parse(bytes.AsSpan()); - } - - /// - /// Parses an ASCII property list from a byte array. - /// - /// The ASCII property list data. - /// The offset at which to start reading the property list. - /// The length of the property list. - /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. - /// When an error occurs during parsing. - public static NSObject Parse(byte[] bytes, int offset, int count) - { - return Parse(bytes.AsSpan(offset, count)); - } - - /// - /// Parses an ASCII property list from a byte span. - /// - /// The ASCII property list data. - /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. - /// When an error occurs during parsing. - public static NSObject Parse(ReadOnlySpan bytes) - { -#if NATIVE_SPAN - return ParseString(Encoding.UTF8.GetString(bytes)); -#else - return ParseString(Encoding.UTF8.GetString(bytes.ToArray())); -#endif - } - - /// - /// Parses an ASCII property list from a string. - /// - /// The ASCII property list data. - /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. - /// When an error occurs during parsing. - public static NSObject ParseString(string value) - { - ASCIIPropertyListParser parser = new ASCIIPropertyListParser(value.ToCharArray()); - return parser.Parse(); - } - - /// - /// A space + /// A space /// public const char WHITESPACE_SPACE = ' '; /// - /// A tabulator + /// A tabulator /// public const char WHITESPACE_TAB = '\t'; /// - /// A newline + /// A newline /// public const char WHITESPACE_NEWLINE = '\n'; /// - /// A carriage return + /// A carriage return /// public const char WHITESPACE_CARRIAGE_RETURN = '\r'; /// - /// Token of NSArray start + /// Token of NSArray start /// public const char ARRAY_BEGIN_TOKEN = '('; /// - /// Token of NSArray end + /// Token of NSArray end /// public const char ARRAY_END_TOKEN = ')'; /// - /// Token of NSArray item delimiter + /// Token of NSArray item delimiter /// public const char ARRAY_ITEM_DELIMITER_TOKEN = ','; /// - /// Token of NSDictionary start + /// Token of NSDictionary start /// public const char DICTIONARY_BEGIN_TOKEN = '{'; /// - /// Token of NSDictionary end + /// Token of NSDictionary end /// public const char DICTIONARY_END_TOKEN = '}'; /// - /// Token of NSDictionary assignment + /// Token of NSDictionary assignment /// public const char DICTIONARY_ASSIGN_TOKEN = '='; /// - /// Token of NSDictionary item delimiter + /// Token of NSDictionary item delimiter /// public const char DICTIONARY_ITEM_DELIMITER_TOKEN = ';'; /// - /// Token of quoted NSString start + /// Token of quoted NSString start /// public const char QUOTEDSTRING_BEGIN_TOKEN = '"'; /// - /// Token of quoted NSString end + /// Token of quoted NSString end /// public const char QUOTEDSTRING_END_TOKEN = '"'; /// - /// Token of quoted NSString escaped character + /// Token of quoted NSString escaped character /// public const char QUOTEDSTRING_ESCAPE_TOKEN = '\\'; /// - /// Token of NSData start + /// Token of NSData start /// public const char DATA_BEGIN_TOKEN = '<'; /// - /// Token of NSData end + /// Token of NSData end /// public const char DATA_END_TOKEN = '>'; /// - /// Token of GSObject start + /// Token of GSObject start /// public const char DATA_GSOBJECT_BEGIN_TOKEN = '*'; /// - /// Token of GSDate start + /// Token of GSDate start /// public const char DATA_GSDATE_BEGIN_TOKEN = 'D'; /// - /// Token of GSBoolean start + /// Token of GSBoolean start /// public const char DATA_GSBOOL_BEGIN_TOKEN = 'B'; /// - /// Token for GSBoolen's true + /// Token for GSBoolen's true /// public const char DATA_GSBOOL_TRUE_TOKEN = 'Y'; /// - /// Token for GSBoolen's false + /// Token for GSBoolen's false /// public const char DATA_GSBOOL_FALSE_TOKEN = 'N'; /// - /// Token for GSInteger + /// Token for GSInteger /// public const char DATA_GSINT_BEGIN_TOKEN = 'I'; /// - /// Token for GSReal + /// Token for GSReal /// public const char DATA_GSREAL_BEGIN_TOKEN = 'R'; /// - /// Token for NSDate date field delimited + /// Token for NSDate date field delimited /// public const char DATE_DATE_FIELD_DELIMITER = '-'; /// - /// Token for NSDate time field delimiter + /// Token for NSDate time field delimiter /// public const char DATE_TIME_FIELD_DELIMITER = ':'; /// - /// Token for GSDate date and time delimiter + /// Token for GSDate date and time delimiter /// public const char DATE_GS_DATE_TIME_DELIMITER = ' '; /// - /// Token for NSDate date and time delimiter + /// Token for NSDate date and time delimiter /// public const char DATE_APPLE_DATE_TIME_DELIMITER = 'T'; /// - /// Token for NSDate end + /// Token for NSDate end /// public const char DATE_APPLE_END_TOKEN = 'Z'; /// - /// Token for comment start + /// Token for comment start /// public const char COMMENT_BEGIN_TOKEN = '/'; /// - /// Second token for multiline comment + /// Second token for multiline comment /// public const char MULTILINE_COMMENT_SECOND_TOKEN = '*'; /// - /// Second token for singleline comment + /// Second token for singleline comment /// public const char SINGLELINE_COMMENT_SECOND_TOKEN = '/'; /// - /// End token for multiline comment + /// End token for multiline comment /// public const char MULTILINE_COMMENT_END_TOKEN = '/'; @@ -283,13 +205,10 @@ namespace Claunia.PropertyList /** * Only allow subclasses to change instantiation. */ - protected ASCIIPropertyListParser() - { - - } + protected ASCIIPropertyListParser() { } /// - /// Creates a new parser for the given property list content. + /// Creates a new parser for the given property list content. /// /// The content of the property list that is to be parsed. ASCIIPropertyListParser(char[] propertyListContent) @@ -298,37 +217,113 @@ namespace Claunia.PropertyList } /// - /// Checks whether the given sequence of symbols can be accepted. + /// Parses an ASCII property list file. + /// + /// The ASCII property list file.. + /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + /// When an error occurs during parsing. + /// When an error occured while reading from the input stream. + public static NSObject Parse(FileInfo f) + { + return Parse(f.OpenRead()); + } + + /// + /// Parses an ASCII property list from an input stream. + /// + /// The input stream that points to the property list's data. + /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + /// When an error occurs during parsing. + /// + 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); + } + + /// + /// Parses an ASCII property list from a byte array. + /// + /// The ASCII property list data. + /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + /// When an error occurs during parsing. + public static NSObject Parse(byte[] bytes) + { + return Parse(bytes.AsSpan()); + } + + /// + /// Parses an ASCII property list from a byte array. + /// + /// The ASCII property list data. + /// The offset at which to start reading the property list. + /// The length of the property list. + /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + /// When an error occurs during parsing. + public static NSObject Parse(byte[] bytes, int offset, int count) + { + return Parse(bytes.AsSpan(offset, count)); + } + + /// + /// Parses an ASCII property list from a byte span. + /// + /// The ASCII property list data. + /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + /// When an error occurs during parsing. + public static NSObject Parse(ReadOnlySpan bytes) + { + #if NATIVE_SPAN + return ParseString(Encoding.UTF8.GetString(bytes)); + #else + return ParseString(Encoding.UTF8.GetString(bytes.ToArray())); + #endif + } + + /// + /// Parses an ASCII property list from a string. + /// + /// The ASCII property list data. + /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. + /// When an error occurs during parsing. + public static NSObject ParseString(string value) + { + ASCIIPropertyListParser parser = new ASCIIPropertyListParser(value.ToCharArray()); + return parser.Parse(); + } + + /// + /// Checks whether the given sequence of symbols can be accepted. /// /// Whether the given tokens occur at the current parsing position. /// The sequence of tokens to look for. bool AcceptSequence(params char[] sequence) { - for (int i = 0; i < sequence.Length; i++) - { - if (data[index + i] != sequence[i]) + for(int i = 0; i < sequence.Length; i++) + if(data[index + i] != sequence[i]) return false; - } + return true; } /// - /// Checks whether the given symbols can be accepted, that is, if one - /// of the given symbols is found at the current parsing position. + /// Checks whether the given symbols can be accepted, that is, if one + /// of the given symbols is found at the current parsing position. /// /// The symbols to check. /// Whether one of the symbols can be accepted or not. bool Accept(params char[] acceptableSymbols) { - bool symbolPresent = false; - foreach (char c in acceptableSymbols) - symbolPresent |= data[index] == c; + bool symbolPresent = false; + foreach(char c in acceptableSymbols) symbolPresent |= data[index] == c; return symbolPresent; } /// - /// Checks whether the given symbol can be accepted, that is, if - /// the given symbols is found at the current parsing position. + /// Checks whether the given symbol can be accepted, that is, if + /// the given symbols is found at the current parsing position. /// /// The symbol to check. /// Whether the symbol can be accepted or not. @@ -338,36 +333,36 @@ namespace Claunia.PropertyList } /// - /// Expects the input to have one of the given symbols at the current parsing position. + /// Expects the input to have one of the given symbols at the current parsing position. /// /// The expected symbols. /// If none of the expected symbols could be found. void Expect(params char[] expectedSymbols) { - if (!Accept(expectedSymbols)) + 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)); } } /// - /// Expects the input to have the given symbol at the current parsing position. + /// Expects the input to have the given symbol at the current parsing position. /// /// The expected symbol. /// If the expected symbol could be found. void Expect(char expectedSymbol) { - if (!Accept(expectedSymbol)) - throw new FormatException(String.Format("Expected '{0}' but found '{1}' at {2}", expectedSymbol, data[index], index)); + if(!Accept(expectedSymbol)) + throw new FormatException(string.Format("Expected '{0}' but found '{1}' at {2}", expectedSymbol, + data[index], index)); } /// - /// Reads an expected symbol. + /// Reads an expected symbol. /// /// The symbol to read. /// If the expected symbol could not be read. @@ -386,7 +381,7 @@ namespace Claunia.PropertyList } /// - /// Skips several symbols + /// Skips several symbols /// /// The amount of symbols to skip. void Skip(int numSymbols) @@ -405,72 +400,74 @@ 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)) + if(AcceptSequence(COMMENT_BEGIN_TOKEN, SINGLELINE_COMMENT_SECOND_TOKEN)) { Skip(2); ReadInputUntil(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE); commentSkipped = true; } //Skip multi line comments "/* ... */" - else if (AcceptSequence(COMMENT_BEGIN_TOKEN, MULTILINE_COMMENT_SECOND_TOKEN)) + else if(AcceptSequence(COMMENT_BEGIN_TOKEN, MULTILINE_COMMENT_SECOND_TOKEN)) { Skip(2); - while (true) + while(true) { - if (AcceptSequence(MULTILINE_COMMENT_SECOND_TOKEN, MULTILINE_COMMENT_END_TOKEN)) + if(AcceptSequence(MULTILINE_COMMENT_SECOND_TOKEN, MULTILINE_COMMENT_END_TOKEN)) { 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 } /// - /// Reads input until one of the given symbols is found. + /// Reads input until one of the given symbols is found. /// /// The input until one the given symbols. /// The symbols that can occur after the string to read. string ReadInputUntil(params char[] symbols) { string s = ""; - while (!Accept(symbols)) + while(!Accept(symbols)) { s += data[index]; Skip(); } + return s; } /// - /// Reads input until the given symbol is found. + /// Reads input until the given symbol is found. /// /// The input until the given symbol. /// The symbol that can occur after the string to read. string ReadInputUntil(char symbol) { - String s = ""; - while (!Accept(symbol)) + string s = ""; + while(!Accept(symbol)) { s += data[index]; Skip(); } + return s; } /// - /// Parses the property list from the beginning and returns the root object - /// of the property list. + /// Parses the property list from the beginning and returns the root object + /// of the property list. /// /// The root object of the property list. This can either be a NSDictionary or a NSArray. /// When an error occured during parsing @@ -478,81 +475,59 @@ 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 + try { return ParseObject(); } + catch(IndexOutOfRangeException) { - 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)); } } /// - /// Parses the NSObject found at the current position in the property list - /// data stream. + /// Parses the NSObject found at the current position in the property list + /// data stream. /// /// The parsed NSObject. - /// + /// NSObject ParseObject() { - switch (data[index]) + 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) + { + 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); } + catch(Exception) { - try - { - return new NSDate(quotedString); - } - catch (Exception) - { - //not a date? --> return string - return new NSString(quotedString); - } + //not a date? --> return string + return new NSString(quotedString); } - 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 - { - //non-numerical -> string or boolean - string parsedString = ParseString(); - return new NSString(parsedString); - } - } + { + //0-9 + if(data[index] > 0x2F && data[index] < 0x3A) return ParseDateString(); + + //non-numerical -> string or boolean + string parsedString = ParseString(); + return new NSString(parsedString); + } } } /// - /// Parses an array from the current parsing position. - /// The prerequisite for calling this method is, that an array begin token has been read. + /// Parses an array from the current parsing position. + /// The prerequisite for calling this method is, that an array begin token has been read. /// /// The array found at the parsing position. NSArray ParseArray() @@ -561,28 +536,24 @@ namespace Claunia.PropertyList Skip(); SkipWhitespacesAndComments(); List objects = new List(); - while (!Accept(ARRAY_END_TOKEN)) + while(!Accept(ARRAY_END_TOKEN)) { 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()); } /// - /// Parses a dictionary from the current parsing position. - /// The prerequisite for calling this method is, that a dictionary begin token has been read. + /// Parses a dictionary from the current parsing position. + /// The prerequisite for calling this method is, that a dictionary begin token has been read. /// /// The dictionary found at the parsing position. NSDictionary ParseDictionary() @@ -591,14 +562,12 @@ namespace Claunia.PropertyList Skip(); SkipWhitespacesAndComments(); NSDictionary dict = new NSDictionary(); - while (!Accept(DICTIONARY_END_TOKEN)) + while(!Accept(DICTIONARY_END_TOKEN)) { //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,15 +580,16 @@ namespace Claunia.PropertyList Read(DICTIONARY_ITEM_DELIMITER_TOKEN); SkipWhitespacesAndComments(); } + //skip end token Skip(); return dict; } /// - /// Parses a data object from the current parsing position. - /// This can either be a NSData object or a GnuStep NSNumber or NSDate. - /// The prerequisite for calling this method is, that a data begin token has been read. + /// Parses a data object from the current parsing position. + /// This can either be a NSData object or a GnuStep NSNumber or NSDate. + /// The prerequisite for calling this method is, that a data begin token has been read. /// /// The data object found at the parsing position. NSObject ParseData() @@ -627,36 +597,36 @@ namespace Claunia.PropertyList NSObject obj = null; //Skip begin token Skip(); - if (Accept(DATA_GSOBJECT_BEGIN_TOKEN)) + if(Accept(DATA_GSOBJECT_BEGIN_TOKEN)) { Skip(); - Expect(DATA_GSBOOL_BEGIN_TOKEN, DATA_GSDATE_BEGIN_TOKEN, DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN); - if (Accept(DATA_GSBOOL_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(); } - else if (Accept(DATA_GSDATE_BEGIN_TOKEN)) + else if(Accept(DATA_GSDATE_BEGIN_TOKEN)) { //Date Skip(); string dateString = ReadInputUntil(DATA_END_TOKEN); obj = new NSDate(dateString); } - else if (Accept(DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN)) + else if(Accept(DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN)) { //Number Skip(); string numberString = ReadInputUntil(DATA_END_TOKEN); obj = new NSNumber(numberString); } + //parse data end token Read(DATA_END_TOKEN); } @@ -665,14 +635,15 @@ namespace Claunia.PropertyList string dataString = ReadInputUntil(DATA_END_TOKEN); dataString = Regex.Replace(dataString, "\\s+", ""); - int numBytes = dataString.Length / 2; - byte[] bytes = new byte[numBytes]; - for (int i = 0; i < bytes.Length; i++) + int numBytes = dataString.Length / 2; + byte[] bytes = new byte[numBytes]; + for(int i = 0; i < bytes.Length; i++) { string byteString = dataString.Substring(i * 2, 2); - int byteValue = Convert.ToInt32(byteString, 16); + int byteValue = Convert.ToInt32(byteString, 16); bytes[i] = (byte)byteValue; } + obj = new NSData(bytes); //skip end token @@ -683,40 +654,38 @@ namespace Claunia.PropertyList } /// - /// Attempts to parse a plain string as a date if possible. + /// Attempts to parse a plain string as a date if possible. /// /// A NSDate if the string represents such an object. Otherwise a NSString is returned. NSObject ParseDateString() { string numericalString = ParseString(); - if (numericalString.Length > 4 && numericalString[4] == DATE_DATE_FIELD_DELIMITER) - { - try - { - return new NSDate(numericalString); - } - catch (Exception) + if(numericalString.Length > 4 && numericalString[4] == DATE_DATE_FIELD_DELIMITER) + 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); } /// - /// Parses a plain string from the current parsing position. - /// The string is made up of all characters to the next whitespace, delimiter token or assignment token. + /// Parses a plain string from the current parsing position. + /// The string is made up of all characters to the next whitespace, delimiter token or assignment token. /// /// The string found at the current parsing position. 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); } /// - /// Parses a quoted string from the current parsing position. - /// The prerequisite for calling this method is, that a quoted string begin token has been read. + /// Parses a quoted string from the current parsing position. + /// The prerequisite for calling this method is, that a quoted string begin token has been read. /// /// The quoted string found at the parsing method with all special characters unescaped. /// If an error occured during parsing. @@ -724,119 +693,109 @@ namespace Claunia.PropertyList { //Skip begin token Skip(); - string quotedString = ""; - bool unescapedBackslash = true; + 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)) - { + if(Accept(QUOTEDSTRING_ESCAPE_TOKEN)) unescapedBackslash = !(data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash); - } Skip(); } + string unescapedString; - try + try { unescapedString = ParseQuotedString(quotedString); } + catch(Exception) { - 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; } /// - /// Parses a string according to the format specified for ASCII property lists. - /// Such strings can contain escape sequences which are unescaped in this method. + /// Parses a string according to the format specified for ASCII property lists. + /// Such strings can contain escape sequences which are unescaped in this method. /// /// The unescaped string in UTF-8 or ASCII format, depending on the contained characters. - /// The escaped string according to the ASCII property list format, without leading and trailing quotation marks. + /// + /// The escaped string according to the ASCII property list format, without leading and trailing quotation + /// marks. + /// /// If the en-/decoder for the UTF-8 or ASCII encoding could not be loaded /// If the string is encoded neither in ASCII nor in UTF-8 public static string ParseQuotedString(string s) { List strBytes = new List(); - var characters = (IEnumerable)s.ToCharArray(); - var c = characters.GetEnumerator(); + IEnumerable characters = s.ToCharArray(); + IEnumerator c = characters.GetEnumerator(); - while (c.MoveNext()) - { - switch (c.Current) + while(c.MoveNext()) + switch(c.Current) { case '\\': - { //An escaped sequence is following - byte[] bts = Encoding.UTF8.GetBytes(ParseEscapedSequence(c)); - foreach (byte b in bts) - strBytes.Add(b); - break; - } + { + //An escaped sequence is following + byte[] bts = Encoding.UTF8.GetBytes(ParseEscapedSequence(c)); + foreach(byte b in bts) strBytes.Add(b); + break; + } default: - { //a normal ASCII char - strBytes.AddRange(Encoding.BigEndianUnicode.GetBytes(new[] { c.Current })); - break; - } + { + //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) + int i = 0; + foreach(byte b in strBytes) { bytArr[i] = b; i++; } + //Build string string result = Encoding.BigEndianUnicode.GetString(bytArr); //If the string can be represented in the ASCII codepage // --> use ASCII encoding - if (IsASCIIEncodable(result)) + 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; } /// - /// Unescapes an escaped character sequence, e.g. \\u00FC. + /// Unescapes an escaped character sequence, e.g. \\u00FC. /// /// The unescaped character as a string. /// The string character iterator pointing to the first character after the backslash /// If an invalid Unicode or ASCII escape sequence is found. - private static string ParseEscapedSequence(IEnumerator iterator) + static string ParseEscapedSequence(IEnumerator 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 = ""; @@ -849,7 +808,7 @@ namespace Claunia.PropertyList byte2 += iterator.Current; iterator.MoveNext(); byte2 += iterator.Current; - byte[] stringBytes = { (byte)Convert.ToInt32(byte1, 16), (byte)Convert.ToInt32(byte2, 16) }; + byte[] stringBytes = {(byte)Convert.ToInt32(byte1, 16), (byte)Convert.ToInt32(byte2, 16)}; return Encoding.UTF8.GetString(stringBytes); } else @@ -861,19 +820,19 @@ namespace Claunia.PropertyList num += iterator.Current; iterator.MoveNext(); num += iterator.Current; - int asciiCode = Convert.ToInt32(num, 8); - byte[] stringBytes = { 0, (byte)asciiCode }; + int asciiCode = Convert.ToInt32(num, 8); + byte[] stringBytes = {0, (byte)asciiCode}; return Encoding.UTF8.GetString(stringBytes); } } internal static bool IsASCIIEncodable(string text) { - foreach (char c in text) - if ((int)c > 0x7F) + foreach(char c in text) + if(c > 0x7F) return false; + return true; } } -} - +} \ No newline at end of file diff --git a/plist-cil/BinaryPropertyListParser.cs b/plist-cil/BinaryPropertyListParser.cs index 33818e8..b700ab8 100644 --- a/plist-cil/BinaryPropertyListParser.cs +++ b/plist-cil/BinaryPropertyListParser.cs @@ -22,61 +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.Buffers.Binary; using System.Diagnostics; -using System.Text; using System.IO; +using System.Numerics; +using System.Text; 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. - /// - /// Parsing is done by calling the static , - /// and methods. - /// + /// + /// Parses property lists that are in Apple's binary format. + /// Use this class when you are sure about the format of the property list. + /// Otherwise use the PropertyListParser class. + /// + /// + /// Parsing is done by calling the static , + /// and methods. + /// /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public class BinaryPropertyListParser { - private readonly static Encoding utf16BigEndian = Encoding.GetEncoding("UTF-16BE"); + static readonly Encoding utf16BigEndian = Encoding.GetEncoding("UTF-16BE"); /// - /// Major version of the property list format + /// Major version of the property list format /// int majorVersion; /// - /// Minor version of the property list format + /// Minor version of the property list format /// int minorVersion; /// - /// Length of an object reference in bytes + /// Length of an object reference in bytes /// int objectRefSize; /// - /// The table holding the information at which offset each object is found + /// The table holding the information at which offset each object is found /// int[] offsetTable; /// - /// Protected constructor so that instantiation is fully controlled by the - /// static parse methods. + /// Protected constructor so that instantiation is fully controlled by the + /// static parse methods. /// - /// - protected BinaryPropertyListParser() - { - } + /// + protected BinaryPropertyListParser() { } /// - /// Parses a binary property list from a byte array. + /// Parses a binary property list from a byte array. /// /// The binary property list's data. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -87,7 +88,7 @@ namespace Claunia.PropertyList } /// - /// Parses a binary property list from a byte array. + /// Parses a binary property list from a byte array. /// /// The binary property list's data. /// The length of the property list. @@ -100,7 +101,7 @@ namespace Claunia.PropertyList } /// - /// Parses a binary property list from a byte span. + /// Parses a binary property list from a byte span. /// /// The binary property list's data. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -112,23 +113,19 @@ namespace Claunia.PropertyList } /// - /// Parses a binary property list from a byte array. + /// Parses a binary property list from a byte array. /// /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. /// The binary property list's data. /// When the property list's format could not be parsed. - private NSObject DoParse(ReadOnlySpan bytes) + NSObject DoParse(ReadOnlySpan 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 @@ -140,22 +137,21 @@ namespace Claunia.PropertyList // 1.5 - Lion // 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 + ". " + - "Version 1.0 and later are not yet supported."); - } + if(majorVersion > 0) + 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 trailer = bytes.Slice(bytes.Length - 32, 32); //6 null bytes (index 0 to 5) int offsetSize = trailer[6]; objectRefSize = trailer[7]; - int numObjects = (int)BinaryPrimitives.ReadUInt64BigEndian(trailer.Slice(8, 8)); - int topObject = (int)BinaryPrimitives.ReadUInt64BigEndian(trailer.Slice(16, 8)); + int numObjects = (int)BinaryPrimitives.ReadUInt64BigEndian(trailer.Slice(8, 8)); + int topObject = (int)BinaryPrimitives.ReadUInt64BigEndian(trailer.Slice(16, 8)); int offsetTableOffset = (int)BinaryPrimitives.ReadUInt64BigEndian(trailer.Slice(24, 8)); /* @@ -163,9 +159,9 @@ namespace Claunia.PropertyList */ offsetTable = new int[numObjects]; - for (int i = 0; i < numObjects; i++) + for(int i = 0; i < numObjects; i++) { - var offsetBytes = bytes.Slice(offsetTableOffset + i * offsetSize, offsetSize); + ReadOnlySpan offsetBytes = bytes.Slice(offsetTableOffset + i * offsetSize, offsetSize); offsetTable[i] = (int)ParseUnsignedInt(offsetBytes); } @@ -173,7 +169,7 @@ namespace Claunia.PropertyList } /// - /// Parses a binary property list from an input stream. + /// Parses a binary property list from an input stream. /// /// The input stream that points to the property list's data. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -188,7 +184,7 @@ namespace Claunia.PropertyList } /// - /// Parses a binary property list file. + /// Parses a binary property list file. /// /// The binary property list file /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -199,218 +195,236 @@ namespace Claunia.PropertyList } /// - /// Parses an object inside the currently parsed binary property list. - /// For the format specification check - /// - /// Apple's binary property list parser implementation. + /// Parses an object inside the currently parsed binary property list. + /// For the format specification check + /// + /// Apple's binary property list parser implementation + /// + /// . /// /// The parsed object. /// The object ID. /// When the property list's format could not be parsed. NSObject ParseObject(ReadOnlySpan bytes, int obj) { - int offset = offsetTable[obj]; - byte type = bytes[offset]; - int objType = (type & 0xF0) >> 4; //First 4 bits - int objInfo = (type & 0x0F); //Second 4 bits - switch (objType) + int offset = offsetTable[obj]; + byte type = bytes[offset]; + int objType = (type & 0xF0) >> 4; //First 4 bits + int objInfo = type & 0x0F; //Second 4 bits + switch(objType) { case 0x0: + { + //Simple + switch(objInfo) { - //Simple - switch (objInfo) + case 0x0: { - case 0x0: - { - //null object (v1.0 and later) - return null; - } - case 0x8: - { - //false - return new NSNumber(false); - } - case 0x9: - { - //true - return new NSNumber(true); - } - case 0xC: - { - //URL with no base URL (v1.0 and later) - //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17) - break; - } - case 0xD: - { - //URL with base URL (v1.0 and later) - //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17) - break; - } - case 0xE: - { - //16-byte UUID (v1.0 and later) - //TODO Implement binary UUID parsing (not yet even implemented in Core Foundation as of revision 855.17) - break; - } - case 0xF: - { - //filler byte - return null; - } + //null object (v1.0 and later) + return null; + } + case 0x8: + { + //false + return new NSNumber(false); + } + case 0x9: + { + //true + return new NSNumber(true); + } + case 0xC: + { + //URL with no base URL (v1.0 and later) + //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17) + break; + } + case 0xD: + { + //URL with base URL (v1.0 and later) + //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17) + break; + } + case 0xE: + { + //16-byte UUID (v1.0 and later) + //TODO Implement binary UUID parsing (not yet even implemented in Core Foundation as of revision 855.17) + break; + } + case 0xF: + { + //filler byte + return null; } - break; } + + break; + } case 0x1: - { - //integer - int length = (int)Math.Pow(2, objInfo); - return new NSNumber(bytes.Slice(offset + 1, length), NSNumber.INTEGER); - } + { + //integer + int length = (int)Math.Pow(2, objInfo); + return new NSNumber(bytes.Slice(offset + 1, length), NSNumber.INTEGER); + } case 0x2: - { - //real - int length = (int)Math.Pow(2, objInfo); - return new NSNumber(bytes.Slice(offset + 1, length), NSNumber.REAL); - } + { + //real + int length = (int)Math.Pow(2, objInfo); + return new NSNumber(bytes.Slice(offset + 1, length), NSNumber.REAL); + } case 0x3: - { - //Date - if (objInfo != 0x3) - { - throw new PropertyListFormatException("The given binary property list contains a date object of an unknown type (" + objInfo + ")"); - } - return new NSDate(bytes.Slice(offset + 1, 8)); - } + { + //Date + if(objInfo != 0x3) + 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: - { - //Data - ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int dataoffset); - return new NSData(CopyOfRange(bytes, offset + dataoffset, offset + dataoffset + length)); - } + { + //Data + ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int dataoffset); + return new NSData(CopyOfRange(bytes, offset + dataoffset, offset + dataoffset + length)); + } case 0x5: - { - //ASCII String, each character is 1 byte - ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int stroffset); - return new NSString(bytes.Slice(offset + stroffset, length), Encoding.ASCII); - } + { + //ASCII String, each character is 1 byte + ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int stroffset); + return new NSString(bytes.Slice(offset + stroffset, length), Encoding.ASCII); + } case 0x6: - { - //UTF-16-BE String - ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int stroffset); + { + //UTF-16-BE String + ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int stroffset); - //UTF-16 characters can have variable length, but the Core Foundation reference implementation - //assumes 2 byte characters, thus only covering the Basic Multilingual Plane - length *= 2; - return new NSString(bytes.Slice(offset + stroffset, length), utf16BigEndian); - } + //UTF-16 characters can have variable length, but the Core Foundation reference implementation + //assumes 2 byte characters, thus only covering the Basic Multilingual Plane + length *= 2; + return new NSString(bytes.Slice(offset + stroffset, length), utf16BigEndian); + } case 0x7: - { - //UTF-8 string (v1.0 and later) - ReadLengthAndOffset(bytes, objInfo, offset, out int strOffset, out int characters); + { + //UTF-8 string (v1.0 and later) + ReadLengthAndOffset(bytes, objInfo, offset, out int strOffset, out int characters); - //UTF-8 characters can have variable length, so we need to calculate the byte length dynamically - //by reading the UTF-8 characters one by one - int length = CalculateUtf8StringLength(bytes, offset + strOffset, characters); - return new NSString(bytes.Slice(offset + strOffset, length), Encoding.UTF8); - } + //UTF-8 characters can have variable length, so we need to calculate the byte length dynamically + //by reading the UTF-8 characters one by one + int length = CalculateUtf8StringLength(bytes, offset + strOffset, characters); + return new NSString(bytes.Slice(offset + strOffset, length), Encoding.UTF8); + } case 0x8: - { - //UID (v1.0 and later) - int length = objInfo + 1; - return new UID(bytes.Slice(offset + 1, length)); - } + { + //UID (v1.0 and later) + int length = objInfo + 1; + return new UID(bytes.Slice(offset + 1, length)); + } case 0xA: + { + //Array + ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int arrayOffset); + + NSArray array = new NSArray(length); + for(int i = 0; i < length; i++) { - //Array - ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int arrayOffset); - - NSArray array = new NSArray(length); - for (int i = 0; i < length; i++) - { - int objRef = (int)ParseUnsignedInt(bytes.Slice(offset + arrayOffset + i * objectRefSize, objectRefSize)); - array.Add(ParseObject(bytes, objRef)); - } - return array; - + int objRef = + (int)ParseUnsignedInt(bytes.Slice(offset + arrayOffset + i * objectRefSize, objectRefSize)); + array.Add(ParseObject(bytes, objRef)); } + + return array; + } case 0xB: - { - //Ordered set (v1.0 and later) - ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int contentOffset); + { + //Ordered set (v1.0 and later) + ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int contentOffset); - NSSet set = new NSSet(true); - for (int i = 0; i < length; i++) - { - int objRef = (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, objectRefSize)); - set.AddObject(ParseObject(bytes, objRef)); - } - return set; + NSSet set = new NSSet(true); + for(int i = 0; i < length; i++) + { + int objRef = + (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, + objectRefSize)); + set.AddObject(ParseObject(bytes, objRef)); } + + return set; + } case 0xC: - { - //Set (v1.0 and later) - ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int contentOffset); + { + //Set (v1.0 and later) + ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int contentOffset); - NSSet set = new NSSet(); - for (int i = 0; i < length; i++) - { - int objRef = (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, objectRefSize)); - set.AddObject(ParseObject(bytes, objRef)); - } - return set; + NSSet set = new NSSet(); + for(int i = 0; i < length; i++) + { + int objRef = + (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, + objectRefSize)); + set.AddObject(ParseObject(bytes, objRef)); } + + return set; + } case 0xD: - { - //Dictionary - ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int contentOffset); + { + //Dictionary + ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int contentOffset); - //System.out.println("Parsing dictionary #"+obj); - 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)); - NSObject key = ParseObject(bytes, keyRef); - NSObject val = ParseObject(bytes, valRef); - dict.Add(key.ToString(), val); - } - return dict; - } - default: + //System.out.println("Parsing dictionary #"+obj); + NSDictionary dict = new NSDictionary(length); + for(int i = 0; i < length; i++) { - Debug.WriteLine("WARNING: The given binary property list contains an object of unknown type (" + objType + ")"); - break; + 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 + + ")"); + break; + } } + return null; } /// - /// Reads the length for arrays, sets and dictionaries. + /// Reads the length for arrays, sets and dictionaries. /// /// An array with the length two. First entry is the length, second entry the offset at which the content starts. /// Object information byte. /// Offset in the byte array at which the object is located. - void ReadLengthAndOffset(ReadOnlySpan bytes, int objInfo, int offset, out int lengthValue, out int offsetValue) + void ReadLengthAndOffset(ReadOnlySpan bytes, int objInfo, int offset, out int lengthValue, + out int offsetValue) { lengthValue = objInfo; offsetValue = 1; - if (objInfo == 0xF) + if(objInfo == 0xF) { 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..."); - } - int intInfo = int_type & 0x0F; + int intType = (int_type & 0xF0) >> 4; + if(intType != 0x1) + 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,13 +433,13 @@ 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); } } } /// - /// Calculates the length in bytes of the UTF-8 string. + /// Calculates the length in bytes of the UTF-8 string. /// /// The UTF-8 string length. /// Array containing the UTF-8 string. @@ -434,76 +448,53 @@ namespace Claunia.PropertyList int CalculateUtf8StringLength(ReadOnlySpan bytes, int offset, int numCharacters) { int length = 0; - for (int i = 0; i < numCharacters; i++) + 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) + 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) + 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; } /// - /// Parses an unsigned integers from a span. + /// Parses an unsigned integers from a span. /// /// The byte array containing the unsigned integer. /// The unsigned integer represented by the given bytes. public static long ParseUnsignedInt(ReadOnlySpan bytes) { - if (bytes.Length <= 4) - { - return ParseLong(bytes); - } - else - { - return ParseLong(bytes) & 0xFFFFFFFFL; - } + if(bytes.Length <= 4) return ParseLong(bytes); + + return ParseLong(bytes) & 0xFFFFFFFFL; } /// - /// Parses an unsigned integers from a byte array. + /// Parses an unsigned integers from a byte array. /// /// The byte array containing the unsigned integer. /// The unsigned integer represented by the given bytes. @@ -513,50 +504,45 @@ namespace Claunia.PropertyList } /// - /// Parses a long from a (big-endian) byte array. + /// Parses a long from a (big-endian) byte array. /// /// The long integer represented by the given bytes. /// The bytes representing the long integer. public static long ParseLong(ReadOnlySpan bytes) { - switch (bytes.Length) + 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}"); } } /// - /// Parses a double from a (big-endian) byte array. + /// Parses a double from a (big-endian) byte array. /// /// The double represented by the given bytes. /// The bytes representing the double. public static double ParseDouble(ReadOnlySpan 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); } /// - /// Copies a part of a byte array into a new array. + /// Copies a part of a byte array into a new array. /// /// The copied array. /// The source array. @@ -565,13 +551,11 @@ namespace Claunia.PropertyList public static byte[] CopyOfRange(ReadOnlySpan src, int startIndex, int endIndex) { int length = endIndex - startIndex; - if (length < 0) - { - throw new ArgumentOutOfRangeException("startIndex (" + startIndex + ")" + " > endIndex (" + endIndex + ")"); - } + if(length < 0) + throw new ArgumentOutOfRangeException("startIndex (" + startIndex + ")" + " > endIndex (" + endIndex + + ")"); return src.Slice(startIndex, endIndex - startIndex).ToArray(); } } -} - +} \ No newline at end of file diff --git a/plist-cil/BinaryPropertyListWriter.AddObjectEqualityComparer.cs b/plist-cil/BinaryPropertyListWriter.AddObjectEqualityComparer.cs index 31ef74f..56b943d 100644 --- a/plist-cil/BinaryPropertyListWriter.AddObjectEqualityComparer.cs +++ b/plist-cil/BinaryPropertyListWriter.AddObjectEqualityComparer.cs @@ -6,45 +6,32 @@ namespace Claunia.PropertyList public partial class BinaryPropertyListWriter { /// - /// The equality comparer which is used when adding an object to the . In most cases, - /// objects are always added. The only exception are very specific strings, which are only added once. + /// The equality comparer which is used when adding an object to the . In + /// most cases, + /// objects are always added. The only exception are very specific strings, which are only added once. /// - private class AddObjectEqualityComparer : EqualityComparer + class AddObjectEqualityComparer : EqualityComparer { 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; - var s = obj as NSString; - if (s != null && BinaryPropertyListWriter.IsSerializationPrimitive(s)) - { - return s.Content.GetHashCode(); - } - else - { - return obj.GetHashCode(); - } + NSString s = obj as NSString; + if(s != null && IsSerializationPrimitive(s)) return s.Content.GetHashCode(); + + return obj.GetHashCode(); } } } diff --git a/plist-cil/BinaryPropertyListWriter.GetObjectEqualityComparer.cs b/plist-cil/BinaryPropertyListWriter.GetObjectEqualityComparer.cs index 9f3eb54..7f99f24 100644 --- a/plist-cil/BinaryPropertyListWriter.GetObjectEqualityComparer.cs +++ b/plist-cil/BinaryPropertyListWriter.GetObjectEqualityComparer.cs @@ -1,19 +1,19 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; namespace Claunia.PropertyList { public partial class BinaryPropertyListWriter { /// - /// The equality comparer which is used when retrieving objects in the . - /// The logic is slightly different from , results in two equivalent objects - /// (UIDs mainly) being added to the . 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 logic exists purely to maintain binary compatibility with Apple's format. + /// The equality comparer which is used when retrieving objects in the . + /// The logic is slightly different from , results in two equivalent objects + /// (UIDs mainly) being added to the . 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 logic exists purely to maintain binary compatibility with Apple's format. /// - private class GetObjectEqualityComparer : EqualityComparer + class GetObjectEqualityComparer : EqualityComparer { public override bool Equals(NSObject x, NSObject y) { @@ -21,51 +21,29 @@ 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(); } } } -} +} \ No newline at end of file diff --git a/plist-cil/BinaryPropertyListWriter.cs b/plist-cil/BinaryPropertyListWriter.cs index 4f14952..8651e23 100644 --- a/plist-cil/BinaryPropertyListWriter.cs +++ b/plist-cil/BinaryPropertyListWriter.cs @@ -22,171 +22,61 @@ // 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 { /// - /// - /// A BinaryPropertyListWriter is a helper class for writing out - /// binary property list files. - /// - /// It contains an output stream and various structures for keeping track - /// of which NSObjects have already been serialized, and where they were - /// put in the file. - /// + /// + /// A BinaryPropertyListWriter is a helper class for writing out + /// binary property list files. + /// + /// + /// It contains an output stream and various structures for keeping track + /// of which NSObjects have already been serialized, and where they were + /// put in the file. + /// /// /// @author Keith Randall /// @author Natalia Portillo public partial class BinaryPropertyListWriter { /// - /// Binary property list version 0.0 + /// Binary property list version 0.0 /// public const int VERSION_00 = 0; /// - /// Binary property list version 1.0 + /// Binary property list version 1.0 /// public const int VERSION_10 = 10; /// - /// Binary property list version 1.5 + /// Binary property list version 1.5 /// public const int VERSION_15 = 15; /// - /// Binary property list version 2.0 + /// Binary property list version 2.0 /// public const int VERSION_20 = 20; - /// - /// 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 . - /// - /// - /// In most scenarios, you want this to be , 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 if you - /// want to maintain binary compatibility with the Apple tools. - /// - public bool ReuseObjectIds - { - get; - set; - } + // map from object to its ID + readonly Dictionary idDict = new Dictionary(new AddObjectEqualityComparer()); + readonly Dictionary idDict2 = new Dictionary(new GetObjectEqualityComparer()); - /// - /// Finds out the minimum binary property list format version that - /// can be used to save the given NSObject tree. - /// - /// Version code - /// Object root. - static int GetMinimumRequiredVersion(NSObject root) - { - int minVersion = VERSION_00; - if (root == null) - { - minVersion = VERSION_10; - } - if (root is NSDictionary) - { - NSDictionary dict = (NSDictionary)root; - foreach (NSObject o in dict.GetDictionary().Values) - { - int v = GetMinimumRequiredVersion(o); - if (v > minVersion) - minVersion = v; - } - } - else if (root is NSArray) - { - NSArray array = (NSArray)root; - foreach (NSObject o in array) - { - int v = GetMinimumRequiredVersion(o); - if (v > minVersion) - minVersion = v; - } - } - else if (root is NSSet) - { - //Sets are only allowed in property lists v1+ - minVersion = VERSION_10; - NSSet set = (NSSet)root; - foreach (NSObject o in set.AllObjects()) - { - int v = GetMinimumRequiredVersion(o); - if (v > minVersion) - minVersion = v; - } - } - return minVersion; - } - - /// - /// Writes a binary plist file with the given object as the root. - /// - /// the file to write to - /// the source of the data to write to the file - /// - public static void Write(FileInfo file, NSObject root) - { - using (FileStream fous = file.OpenWrite()) - { - Write(fous, root); - } - } - - /// - /// Writes a binary plist serialization of the given object as the root. - /// - /// the stream to write to - /// the source of the data to write to the stream - /// - public static void Write(Stream outStream, NSObject root) - { - int minVersion = GetMinimumRequiredVersion(root); - if (minVersion > VERSION_00) - { - string versionString = ((minVersion == VERSION_10) ? "v1.0" : ((minVersion == VERSION_15) ? "v1.5" : ((minVersion == VERSION_20) ? "v2.0" : "v0.0"))); - throw new IOException("The given property list structure cannot be saved. " + - "The required version of the binary format (" + versionString + ") is not yet supported."); - } - BinaryPropertyListWriter w = new BinaryPropertyListWriter(outStream, minVersion); - w.Write(root); - } - - /// - /// Writes a binary plist serialization of the given object as the root - /// into a byte array. - /// - /// The byte array containing the serialized property list - /// The root object of the property list - /// - public static byte[] WriteToArray(NSObject root) - { - MemoryStream bout = new MemoryStream(); - Write(bout, root); - return bout.ToArray(); - } - - int version = VERSION_00; + // # of bytes written so far + long count; + int currentId; + int idSizeInBytes; // raw output stream to result file Stream outStream; - // # of bytes written so far - long count; - - // map from object to its ID - readonly Dictionary idDict = new Dictionary(new AddObjectEqualityComparer()); - readonly Dictionary idDict2 = new Dictionary(new GetObjectEqualityComparer()); - int currentId = 0; - int idSizeInBytes; + int version = VERSION_00; /// - /// Creates a new binary property list writer + /// Creates a new binary property list writer /// /// The output stream into which the binary property list will be written /// If an error occured while writing to the stream @@ -198,37 +88,145 @@ namespace Claunia.PropertyList public BinaryPropertyListWriter(Stream outStr, int version) { this.version = version; - outStream = outStr; + outStream = outStr; + } + + /// + /// 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 + /// . + /// + /// + /// In most scenarios, you want this to be , 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 + /// if you + /// want to maintain binary compatibility with the Apple tools. + /// + public bool ReuseObjectIds { get; set; } + + /// + /// Finds out the minimum binary property list format version that + /// can be used to save the given NSObject tree. + /// + /// Version code + /// Object root. + static int GetMinimumRequiredVersion(NSObject root) + { + int minVersion = VERSION_00; + if(root == null) minVersion = VERSION_10; + if(root is NSDictionary) + { + NSDictionary dict = (NSDictionary)root; + foreach(NSObject o in dict.GetDictionary().Values) + { + int v = GetMinimumRequiredVersion(o); + if(v > minVersion) minVersion = v; + } + } + else if(root is NSArray) + { + NSArray array = (NSArray)root; + foreach(NSObject o in array) + { + int v = GetMinimumRequiredVersion(o); + if(v > minVersion) minVersion = v; + } + } + else if(root is NSSet) + { + //Sets are only allowed in property lists v1+ + minVersion = VERSION_10; + NSSet set = (NSSet)root; + foreach(NSObject o in set.AllObjects()) + { + int v = GetMinimumRequiredVersion(o); + if(v > minVersion) minVersion = v; + } + } + + return minVersion; + } + + /// + /// Writes a binary plist file with the given object as the root. + /// + /// the file to write to + /// the source of the data to write to the file + /// + public static void Write(FileInfo file, NSObject root) + { + using(FileStream fous = file.OpenWrite()) Write(fous, root); + } + + /// + /// Writes a binary plist serialization of the given object as the root. + /// + /// the stream to write to + /// the source of the data to write to the stream + /// + public static void Write(Stream outStream, NSObject root) + { + int minVersion = GetMinimumRequiredVersion(root); + if(minVersion > VERSION_00) + { + string versionString = minVersion == VERSION_10 + ? "v1.0" + : (minVersion == VERSION_15 + ? "v1.5" + : (minVersion == VERSION_20 ? "v2.0" : "v0.0")); + throw new IOException("The given property list structure cannot be saved. " + + "The required version of the binary format (" + versionString + + ") is not yet supported."); + } + + BinaryPropertyListWriter w = new BinaryPropertyListWriter(outStream, minVersion); + w.Write(root); + } + + /// + /// Writes a binary plist serialization of the given object as the root + /// into a byte array. + /// + /// The byte array containing the serialized property list + /// The root object of the property list + /// + public static byte[] WriteToArray(NSObject root) + { + MemoryStream bout = new MemoryStream(); + Write(bout, root); + return bout.ToArray(); } public void Write(NSObject root) { // magic bytes - Write(new[] { (byte)'b', (byte)'p', (byte)'l', (byte)'i', (byte)'s', (byte)'t' }); + Write(new[] {(byte)'b', (byte)'p', (byte)'l', (byte)'i', (byte)'s', (byte)'t'}); //version - switch (version) + switch(version) { case VERSION_00: - { - Write(new[] { (byte)'0', (byte)'0' }); - break; - } + { + Write(new[] {(byte)'0', (byte)'0'}); + break; + } case VERSION_10: - { - Write(new[] { (byte)'1', (byte)'0' }); - break; - } + { + Write(new[] {(byte)'1', (byte)'0'}); + break; + } case VERSION_15: - { - Write(new[] { (byte)'1', (byte)'5' }); - break; - } + { + Write(new[] {(byte)'1', (byte)'5'}); + break; + } case VERSION_20: - { - Write(new[] { (byte)'2', (byte)'0' }); - break; - } + { + Write(new[] {(byte)'2', (byte)'0'}); + break; + } } // assign IDs to all the objects. @@ -240,30 +238,21 @@ namespace Claunia.PropertyList long[] offsets = new long[idDict.Count]; // write each object, save offset - foreach (var pair in idDict) + foreach(KeyValuePair pair in idDict) { NSObject obj = pair.Key; - int id = pair.Value; + 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); - } + int offsetSizeInBytes = ComputeOffsetSizeInBytes(count); + foreach(long offset in offsets) WriteBytes(offset, offsetSizeInBytes); - if (version != VERSION_15) + if(version != VERSION_15) { // write trailer // 6 null bytes @@ -286,70 +275,51 @@ 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 - { - return idDict2[obj]; - } + 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); - } - else if (value < 256) + if(value < 15) Write((kind << 4) + value); + else if(value < 256) { Write((kind << 4) + 15); Write(0x10); WriteBytes(value, 1); } - else if (value < 65536) + else if(value < 65536) { Write((kind << 4) + 15); Write(0x11); @@ -379,21 +349,18 @@ namespace Claunia.PropertyList internal void Write(Span bytes) { -#if SPAN_NATIVE + #if SPAN_NATIVE outStream.Write(bytes); count += bytes.Length; #else - this.Write(bytes.ToArray()); -#endif + 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) @@ -441,5 +398,4 @@ namespace Claunia.PropertyList return n.isBoolean(); } } -} - +} \ No newline at end of file diff --git a/plist-cil/NSArray.IList.cs b/plist-cil/NSArray.IList.cs index 5d5b813..be1a9ff 100644 --- a/plist-cil/NSArray.IList.cs +++ b/plist-cil/NSArray.IList.cs @@ -18,121 +18,108 @@ // 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 { partial class NSArray : IList { - /// + /// public NSObject this[int index] { - get - { - return this.array[index]; - } + get => array[index]; - set - { - this.array[index] = value; - } + set => array[index] = value; } - /// - public bool IsReadOnly - { - get - { - return false; - } - } + /// + public bool IsReadOnly => false; - public void Add(object item) - { - this.Add(NSObject.Wrap(item)); - } - - /// + /// public void Add(NSObject item) { - this.array.Add(item); + array.Add(item); } - /// + /// public void Clear() { - this.array.Clear(); + array.Clear(); } - public bool Contains(object item) - { - return this.Contains(NSObject.Wrap(item)); - } - - /// + /// public bool Contains(NSObject item) { - return this.array.Contains(item); + return array.Contains(item); } - /// + /// public void CopyTo(NSObject[] array, int arrayIndex) { this.array.CopyTo(array, arrayIndex); } - /// + /// public IEnumerator GetEnumerator() { - return this.array.GetEnumerator(); + return array.GetEnumerator(); + } + + /// + public int IndexOf(NSObject item) + { + return array.IndexOf(item); + } + + /// + public void Insert(int index, NSObject item) + { + array.Insert(index, item); + } + + /// + public bool Remove(NSObject item) + { + return array.Remove(item); + } + + /// + public void RemoveAt(int index) + { + array.RemoveAt(index); + } + + /// + IEnumerator IEnumerable.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 this.array.IndexOf(NSObject.Wrap(item)); - } - - /// - public int IndexOf(NSObject item) - { - return this.array.IndexOf(item); + return array.IndexOf(Wrap(item)); } public void Insert(int index, object item) { - this.Insert(index, NSObject.Wrap(item)); - } - - /// - public void Insert(int index, NSObject item) - { - this.array.Insert(index, item); + Insert(index, Wrap(item)); } public bool Remove(object item) { - return this.Remove(NSObject.Wrap(item)); - } - - /// - public bool Remove(NSObject item) - { - return this.array.Remove(item); - } - - /// - public void RemoveAt(int index) - { - this.array.RemoveAt(index); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return this.array.GetEnumerator(); + return Remove(Wrap(item)); } } -} +} \ No newline at end of file diff --git a/plist-cil/NSArray.cs b/plist-cil/NSArray.cs index c021555..545f360 100644 --- a/plist-cil/NSArray.cs +++ b/plist-cil/NSArray.cs @@ -22,15 +22,15 @@ // 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 { /// - /// Represents an Array. + /// Represents an Array. /// /// @author Daniel Dreibrodt /// @author Natalia Portillo @@ -39,7 +39,7 @@ namespace Claunia.PropertyList List array; /// - /// Creates an empty array of the given length. + /// Creates an empty array of the given length. /// /// The number of elements this array will be able to hold. public NSArray(int length) @@ -48,7 +48,7 @@ namespace Claunia.PropertyList } /// - /// Creates a array from an existing one + /// Creates a array from an existing one /// /// The array which should be wrapped by the NSArray. public NSArray(params NSObject[] a) @@ -57,7 +57,13 @@ namespace Claunia.PropertyList } /// - /// Returns the object stored at the given index. + /// Returns the size of the array. + /// + /// The number of elements that this array can store. + public int Count => array.Count; + + /// + /// Returns the object stored at the given index. /// /// The object at the given index. /// The index of the object. @@ -68,33 +74,33 @@ namespace Claunia.PropertyList } /// - /// Remove the i-th element from the array. - /// The array will be resized. + /// Remove the i-th element from the array. + /// The array will be resized. /// /// The index of the object [Obsolete] public void Remove(int i) { - this.array.RemoveAt(i); + array.RemoveAt(i); } /// - /// Stores an object at the specified index. - /// If there was another object stored at that index it will be replaced. + /// Stores an object at the specified index. + /// If there was another object stored at that index it will be replaced. /// /// The index where to store the object. /// The object. [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); } /// - /// Returns the array of NSObjects represented by this NSArray. - /// Any changes to the values of this array will also affect the NSArray. + /// Returns the array of NSObjects represented by this NSArray. + /// Any changes to the values of this array will also affect the NSArray. /// /// The actual array represented by this NSArray. [Obsolete] @@ -104,82 +110,61 @@ namespace Claunia.PropertyList } /// - /// Returns the size of the array. - /// - /// The number of elements that this array can store. - public int Count - { - get - { - return array.Count; - } - } - - /// - /// Checks whether an object is present in the array or whether it is equal - /// to any of the objects in the array. + /// Checks whether an object is present in the array or whether it is equal + /// to any of the objects in the array. /// /// true, when the object could be found. false otherwise. /// The object to look for. [Obsolete] - public bool ContainsObject(Object obj) + public bool ContainsObject(object obj) { - NSObject nso = NSObject.Wrap(obj); - foreach (NSObject elem in array) - { - if (elem.Equals(nso)) - { + NSObject nso = Wrap(obj); + foreach(NSObject elem in array) + if(elem.Equals(nso)) return true; - } - } + return false; } /// - /// Searches for an object in the array. If it is found its index will be - /// returned. This method also returns an index if the object is not the same - /// as the one stored in the array but has equal contents. + /// Searches for an object in the array. If it is found its index will be + /// returned. This method also returns an index if the object is not the same + /// as the one stored in the array but has equal contents. /// /// The index of the object, if it was found. -1 otherwise. /// The object to look for. [Obsolete] - public int IndexOfObject(Object obj) + public int IndexOfObject(object obj) { - NSObject nso = NSObject.Wrap(obj); - for (int i = 0; i < array.Count; i++) - { - if (array[i].Equals(nso)) - { + NSObject nso = Wrap(obj); + for(int i = 0; i < array.Count; i++) + if(array[i].Equals(nso)) return i; - } - } + return -1; } /// - /// Searches for an object in the array. If it is found its index will be - /// returned. This method only returns the index of an object that is - /// identical to the given one. Thus objects that might contain the - /// same value as the given one will not be considered. + /// Searches for an object in the array. If it is found its index will be + /// returned. This method only returns the index of an object that is + /// identical to the given one. Thus objects that might contain the + /// same value as the given one will not be considered. /// /// The index of the object, if it was found. -1 otherwise. /// The object to look for. [Obsolete] - public int IndexOfIdenticalObject(Object obj) + public int IndexOfIdenticalObject(object obj) { - NSObject nso = NSObject.Wrap(obj); - for (int i = 0; i < array.Count; i++) - { - if (array[i] == nso) - { + NSObject nso = Wrap(obj); + for(int i = 0; i < array.Count; i++) + if(array[i] == nso) return i; - } - } + return -1; } /// - /// Returns the last object contained in this array. + /// Returns the last object contained in this array. /// /// The value of the highest index in the array. public NSObject LastObject() @@ -188,8 +173,8 @@ namespace Claunia.PropertyList } /// - /// Returns a new array containing only the values stored at the given - /// indices. The values are sorted by their index. + /// Returns a new array containing only the values stored at the given + /// indices. The values are sorted by their index. /// /// The new array containing the objects stored at the given indices. /// The indices of the objects. @@ -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; } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals(Object obj) + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// + 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; } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a - /// hash table. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + /// public override int GetHashCode() { int hash = 7; @@ -241,12 +226,13 @@ namespace Claunia.PropertyList { Indent(xml, level); xml.Append(""); - xml.Append(NSObject.NEWLINE); - foreach (NSObject o in array) + 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(""); } @@ -254,30 +240,26 @@ 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)); } /// - /// - /// Generates a valid ASCII property list which has this NSArray 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 - /// Property List Programming Guide - Old-Style ASCII Property Lists. - /// + /// + /// Generates a valid ASCII property list which has this NSArray 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 + /// Property List Programming Guide - Old-Style ASCII Property Lists. + /// /// /// ASCII representation of this object. public string ToASCIIPropertyList() @@ -289,14 +271,16 @@ namespace Claunia.PropertyList } /// - /// - /// Generates a valid ASCII property list in GnuStep format which has this - /// NSArray 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 - /// GnuStep - NSPropertyListSerialization class documentation. - /// + /// + /// Generates a valid ASCII property list in GnuStep format which has this + /// NSArray 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 + /// GnuStep - NSPropertyListSerialization class documentation. + /// /// /// GnuStep ASCII representation of this object. public string ToGnuStepASCIIPropertyList() @@ -312,11 +296,11 @@ namespace Claunia.PropertyList Indent(ascii, level); ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN); int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE, StringComparison.Ordinal); - for (int i = 0; i < array.Count; i++) + 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,20 +308,19 @@ 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) + if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) { ascii.Append(NEWLINE); indexOfLastNewLine = ascii.Length; } } + ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN); } @@ -346,11 +329,11 @@ namespace Claunia.PropertyList Indent(ascii, level); ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN); int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE, StringComparison.Ordinal); - for (int i = 0; i < array.Count; i++) + 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,43 +341,45 @@ 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) + if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) { ascii.Append(NEWLINE); indexOfLastNewLine = ascii.Length; } } + ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN); } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// 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])) + for(int i = 0; i < array.Count; i++) + if(!array[i].Equals(((NSArray)obj)[i])) return false; return true; } } -} - +} \ No newline at end of file diff --git a/plist-cil/NSData.cs b/plist-cil/NSData.cs index 3f22d91..3151ace 100644 --- a/plist-cil/NSData.cs +++ b/plist-cil/NSData.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.IO; using System.Text; @@ -29,7 +30,7 @@ using System.Text; namespace Claunia.PropertyList { /// - /// NSData objects are wrappers for byte buffers + /// NSData objects are wrappers for byte buffers /// /// @author Daniel Dreibrodt /// @author Natalia Portillo @@ -37,117 +38,109 @@ 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; /// - /// Creates the NSData object from the binary representation of it. + /// Creates the NSData object from the binary representation of it. /// /// The raw data contained in the NSData object. public NSData(byte[] bytes) { - this.bytes = bytes; + Bytes = bytes; } /// - /// Creates a NSData object from its textual representation, which is a Base64 encoded amount of bytes. + /// Creates a NSData object from its textual representation, which is a Base64 encoded amount of bytes. /// /// The Base64 encoded contents of the NSData object. /// When the given string is not a proper Base64 formatted string. public NSData(string base64) { - bytes = Convert.FromBase64String(base64); + Bytes = Convert.FromBase64String(base64); } /// - /// Creates a NSData object from a file. Using the files contents as the contents of this NSData object. + /// Creates a NSData object from a file. Using the files contents as the contents of this NSData object. /// /// The file containing the data. /// If the file could not be found. /// If the file could not be read. 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); } /// - /// The bytes contained in this NSData object. + /// The bytes contained in this NSData object. /// /// The data as bytes - public byte[] Bytes - { - get - { - return bytes; - } - } + public byte[] Bytes { get; } /// - /// Gets the amount of data stored in this object. + /// Gets the amount of data stored in this object. /// /// The number of bytes contained in this object. - public int Length - { - get - { - return bytes.Length; - } - } + public int Length => Bytes.Length; /// - /// Loads the bytes from this NSData object into a byte buffer. + /// Loads the bytes from this NSData object into a byte buffer. /// /// The byte buffer which will contain the data /// The amount of data to copy 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)); } /// - /// Loads the bytes from this NSData object into a byte buffer. + /// Loads the bytes from this NSData object into a byte buffer. /// /// The byte buffer which will contain the data /// The start index. /// The stop index. 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)); } /// - /// Gets the Base64 encoded data contained in this NSData object. + /// Gets the Base64 encoded data contained in this NSData object. /// /// The Base64 encoded data as a string. public string GetBase64EncodedData() { - return Convert.ToBase64String(bytes); + return Convert.ToBase64String(Bytes); } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals(Object obj) + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// + 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); } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a - /// hash table. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + /// 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(""); - 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) + 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(""); } 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)); - if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) + 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 } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// 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); } } -} - +} \ No newline at end of file diff --git a/plist-cil/NSDate.cs b/plist-cil/NSDate.cs index e4909fb..45b4ad1 100644 --- a/plist-cil/NSDate.cs +++ b/plist-cil/NSDate.cs @@ -22,20 +22,20 @@ // 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 { /// - /// Represents a date + /// Represents a date /// /// @author Daniel Dreibrodt /// @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,29 +43,59 @@ 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; /// - /// Parses the XML date string and creates a .NET DateTime object from it. + /// Creates a date from its binary representation. + /// + /// bytes The date bytes + public NSDate(ReadOnlySpan bytes) + { + //dates are 8 byte big-endian double, seconds since the epoch + Date = EPOCH.AddSeconds(BinaryPropertyListParser.ParseDouble(bytes)); + } + + /// + /// Parses a date from its textual representation. + /// That representation has the following pattern: yyyy-MM-dd'T'HH:mm:ss'Z' + /// + /// The textual representation of the date (ISO 8601 format) + /// When the date could not be parsed, i.e. it does not match the expected pattern. + public NSDate(string textRepresentation) + { + Date = ParseDateString(textRepresentation); + } + + /// + /// Creates a NSDate from a .NET DateTime + /// + /// The date + public NSDate(DateTime d) + { + Date = d; + } + + /// + /// Gets the date. + /// + /// The date. + public DateTime Date { get; } + + /// + /// Parses the XML date string and creates a .NET DateTime object from it. /// /// The parsed Date /// The date string as found in the XML property list /// Given string cannot be parsed 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); } } /// - /// Generates a String representation of a .NET DateTime object. The string - /// is formatted according to the specification for XML property list dates. + /// Generates a String representation of a .NET DateTime object. The string + /// is formatted according to the specification for XML property list dates. /// /// The date which should be represented. /// The string representation of the date. @@ -75,9 +105,9 @@ namespace Claunia.PropertyList } /// - /// Generates a String representation of a .NET DateTime object. The string - /// is formatted according to the specification for GnuStep ASCII property - /// list dates. + /// Generates a String representation of a .NET DateTime object. The string + /// is formatted according to the specification for GnuStep ASCII property + /// list dates. /// /// The date which should be represented. /// The string representation of the date. @@ -87,96 +117,62 @@ namespace Claunia.PropertyList } /// - /// Creates a date from its binary representation. + /// Determines whether the specified is equal to the current + /// . /// - /// bytes The date bytes - public NSDate(ReadOnlySpan bytes) + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// + public override bool Equals(object obj) { - //dates are 8 byte big-endian double, seconds since the epoch - date = EPOCH.AddSeconds(BinaryPropertyListParser.ParseDouble(bytes)); + return obj.GetType().Equals(GetType()) && Date.Equals(((NSDate)obj).Date); } /// - /// Parses a date from its textual representation. - /// That representation has the following pattern: yyyy-MM-dd'T'HH:mm:ss'Z' + /// Serves as a hash function for a object. /// - /// The textual representation of the date (ISO 8601 format) - /// When the date could not be parsed, i.e. it does not match the expected pattern. - public NSDate(String textRepresentation) - { - date = ParseDateString(textRepresentation); - } - - /// - /// Creates a NSDate from a .NET DateTime - /// - /// The date - public NSDate(DateTime d) - { - date = d; - } - - /// - /// Gets the date. - /// - /// The date. - public DateTime Date - { - get - { - return date; - } - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals(Object obj) - { - return obj.GetType().Equals(GetType()) && date.Equals(((NSDate)obj).Date); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a - /// hash table. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + /// public override int GetHashCode() { - return date.GetHashCode(); + return Date.GetHashCode(); } internal override void ToXml(StringBuilder xml, int level) { Indent(xml, level); xml.Append(""); - xml.Append(MakeDateString(date)); + xml.Append(MakeDateString(Date)); xml.Append(""); } internal override void ToBinary(BinaryPropertyListWriter outPlist) { outPlist.Write(0x33); - outPlist.WriteDouble((date - EPOCH).TotalSeconds); + outPlist.WriteDouble((Date - EPOCH).TotalSeconds); } /// - /// Generates a string representation of the date. + /// Generates a string representation of the date. /// /// A string representation of the date. - 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(">"); } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// 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); } } -} - +} \ No newline at end of file diff --git a/plist-cil/NSDictionary.cs b/plist-cil/NSDictionary.cs index 721dd4f..838b696 100644 --- a/plist-cil/NSDictionary.cs +++ b/plist-cil/NSDictionary.cs @@ -22,22 +22,26 @@ // 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 { /// - /// - /// 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. - /// - /// You can access the keys through the function . - /// - /// Access to the objects stored for each key is given through the function - /// . - /// + /// + /// 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. + /// + /// + /// You can access the keys through the function . + /// + /// + /// Access to the objects stored for each key is given through the function + /// . + /// /// /// @author Daniel Dreibrodt /// @author Natalia Portillo @@ -50,10 +54,10 @@ namespace Claunia.PropertyList readonly Dictionary keys; /// - /// Creates a new empty NSDictionary with a specific capacity. + /// Creates a new empty NSDictionary with a specific capacity. /// /// - /// The capacity of the dictionary. + /// The capacity of the dictionary. /// public NSDictionary(int capacity) { @@ -62,17 +66,38 @@ namespace Claunia.PropertyList } /// - /// Creates a new empty NSDictionary. + /// Creates a new empty NSDictionary. /// - public NSDictionary() - : this(0) - { - } + public NSDictionary() : this(0) { } /// - /// Gets the hashmap which stores the keys and values of this dictionary. - /// Changes to the hashmap's contents are directly reflected in this - /// dictionary. + /// Gets a value indicating whether this instance is empty. + /// + /// true if this instance is empty; otherwise, false. + public bool IsEmpty => dict.Count == 0; + + #region IEnumerable implementation + /// + /// Gets the enumerator. + /// + /// The enumerator. + public IEnumerator> GetEnumerator() + { + return dict.GetEnumerator(); + } + #endregion + + #region IEnumerable implementation + IEnumerator IEnumerable.GetEnumerator() + { + return dict.GetEnumerator(); + } + #endregion + + /// + /// Gets the hashmap which stores the keys and values of this dictionary. + /// Changes to the hashmap's contents are directly reflected in this + /// dictionary. /// /// The hashmap which is used by this dictionary to store its contents. public Dictionary GetDictionary() @@ -81,7 +106,7 @@ namespace Claunia.PropertyList } /// - /// Gets the NSObject stored for the given key. + /// Gets the NSObject stored for the given key. /// /// The object. /// The key. @@ -92,77 +117,68 @@ namespace Claunia.PropertyList } /// - /// Gets a value indicating whether this instance is empty. - /// - /// true if this instance is empty; otherwise, false. - public bool IsEmpty - { - get - { - return dict.Count == 0; - } - } - - /// - /// Checks if the specified object key is contained in the current instance. + /// Checks if the specified object key is contained in the current instance. /// /// true, if key is contained, false otherwise. /// Key. - public bool ContainsKey(Object key) + public bool ContainsKey(object key) { return key is string && dict.ContainsKey((string)key); } /// - /// Removes the item corresponding to the specified key from the current instance, if found. + /// Removes the item corresponding to the specified key from the current instance, if found. /// /// Key. /// true, if removed, false otherwise. - public bool Remove(Object key) + public bool Remove(object key) { return key is string && dict.Remove((string)key); } /// - /// Gets the corresponding to the specified key from the current instance. + /// Gets the corresponding to the specified key from the current instance. /// /// Key. /// The object corresponding to the specified key, null if not found in the current instance. - 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; } /// - /// Checks if the current instance contains the object corresponding to the specified key. + /// Checks if the current instance contains the object corresponding to the specified key. /// /// true, if value is contained, false otherwise. /// Object to search up in the current instance. - 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); } /// - /// Puts a new key-value pair into this dictionary. - /// If the value is null, no operation will be performed on the dictionary. + /// Puts a new key-value pair into this dictionary. + /// If the value is null, no operation will be performed on the dictionary. /// /// The key. - /// The value. Supported object types are numbers, byte-arrays, dates, strings and arrays or sets of those. - public void Add(String key, Object obj) + /// + /// The value. Supported object types are numbers, byte-arrays, dates, strings and arrays or sets of + /// those. + /// + public void Add(string key, object obj) { - if (obj == null) - return; - Add(key, NSObject.Wrap(obj)); + if(obj == null) return; + + Add(key, Wrap(obj)); } /// - /// Puts a new key-value pair into this dictionary. + /// Puts a new key-value pair into this dictionary. /// /// The key. /// The value. @@ -172,7 +188,7 @@ namespace Claunia.PropertyList } /// - /// Puts a new key-value pair into this dictionary. + /// Puts a new key-value pair into this dictionary. /// /// The key. /// The value. @@ -182,7 +198,7 @@ namespace Claunia.PropertyList } /// - /// Puts a new key-value pair into this dictionary. + /// Puts a new key-value pair into this dictionary. /// /// The key. /// The value. @@ -192,153 +208,145 @@ namespace Claunia.PropertyList } /// - /// Checks whether a given value is contained in this dictionary. + /// Checks whether a given value is contained in this dictionary. /// /// The value that will be searched for. /// Whether the key is contained in this dictionary. public bool ContainsValue(string val) { - foreach (NSObject o in dict.Values) - { - if (o.GetType().Equals(typeof(NSString))) + 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; } /// - /// Checks whether a given value is contained in this dictionary. + /// Checks whether a given value is contained in this dictionary. /// /// The value that will be searched for. /// Whether the key is contained in this dictionary. public bool ContainsValue(long val) { - foreach (NSObject o in dict.Values) - { - if (o.GetType().Equals(typeof(NSNumber))) + 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; } /// - /// Checks whether a given value is contained in this dictionary. + /// Checks whether a given value is contained in this dictionary. /// /// The value that will be searched for. /// Whether the key is contained in this dictionary. public bool ContainsValue(double val) { - foreach (NSObject o in dict.Values) - { - if (o.GetType().Equals(typeof(NSNumber))) + 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; } /// - /// Checks whether a given value is contained in this dictionary. + /// Checks whether a given value is contained in this dictionary. /// /// The value that will be searched for. /// Whether the key is contained in this dictionary. public bool ContainsValue(bool val) { - foreach (NSObject o in dict.Values) - { - if (o.GetType().Equals(typeof(NSNumber))) + 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; } /// - /// Checks whether a given value is contained in this dictionary. + /// Checks whether a given value is contained in this dictionary. /// /// The value that will be searched for. /// Whether the key is contained in this dictionary. public bool ContainsValue(DateTime val) { - foreach (NSObject o in dict.Values) - { - if (o.GetType().Equals(typeof(NSDate))) + 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; } /// - /// Checks whether a given value is contained in this dictionary. + /// Checks whether a given value is contained in this dictionary. /// /// The value that will be searched for. /// Whether the key is contained in this dictionary. public bool ContainsValue(byte[] val) { - foreach (NSObject o in dict.Values) - { - if (o.GetType().Equals(typeof(NSData))) + 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; } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// 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; - foreach (KeyValuePair kvp in dict) + foreach(KeyValuePair kvp in dict) { 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; } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a - /// hash table. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + /// public override int GetHashCode() { int hash = 7; @@ -350,28 +358,27 @@ namespace Claunia.PropertyList { Indent(xml, level); xml.Append(""); - xml.Append(NSObject.NEWLINE); - foreach (KeyValuePair kvp in dict) + xml.Append(NEWLINE); + foreach(KeyValuePair kvp in dict) { Indent(xml, level + 1); xml.Append(""); //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 (kvp.Key.Contains("&") || kvp.Key.Contains("<") || kvp.Key.Contains(">")) + if(kvp.Key.Contains("&") || kvp.Key.Contains("<") || kvp.Key.Contains(">")) { xml.Append("", "]]]]>")); xml.Append("]]>"); } - else - { - xml.Append(kvp.Key); - } + else xml.Append(kvp.Key); + xml.Append(""); - 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(""); } @@ -380,35 +387,24 @@ namespace Claunia.PropertyList { base.AssignIDs(outPlist); - foreach (KeyValuePair entry in dict) - { - keys[entry.Key].AssignIDs(outPlist); - } + foreach(KeyValuePair entry in dict) keys[entry.Key].AssignIDs(outPlist); - foreach (KeyValuePair entry in dict) - { - entry.Value.AssignIDs(outPlist); - } + foreach(KeyValuePair entry in dict) entry.Value.AssignIDs(outPlist); } internal override void ToBinary(BinaryPropertyListWriter outPlist) { outPlist.WriteIntHeader(0xD, dict.Count); - foreach (KeyValuePair entry in dict) - { - outPlist.WriteID(outPlist.GetID(keys[entry.Key])); - } - foreach (KeyValuePair entry in dict) - { - outPlist.WriteID(outPlist.GetID(entry.Value)); - } + foreach(KeyValuePair entry in dict) outPlist.WriteID(outPlist.GetID(keys[entry.Key])); + foreach(KeyValuePair entry in dict) outPlist.WriteID(outPlist.GetID(entry.Value)); } /// - /// 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 - /// Property List Programming Guide - Old-Style ASCII Property Lists. + /// 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 + /// Property List Programming Guide - Old-Style ASCII Property Lists. /// /// ASCII representation of this object. public string ToASCIIPropertyList() @@ -420,10 +416,11 @@ namespace Claunia.PropertyList } /// - /// 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 - /// GnuStep - NSPropertyListSerialization class documentation. + /// 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 + /// GnuStep - NSPropertyListSerialization class documentation. /// /// GnuStep ASCII representation of this object. public string ToGnuStepASCIIPropertyList() @@ -439,7 +436,7 @@ namespace Claunia.PropertyList Indent(ascii, level); ascii.Append(ASCIIPropertyListParser.DICTIONARY_BEGIN_TOKEN); ascii.Append(NEWLINE); - foreach (string key in Keys) + foreach(string key in Keys) { NSObject val = ObjectForKey(key); Indent(ascii, level + 1); @@ -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); } @@ -469,7 +469,7 @@ namespace Claunia.PropertyList Indent(ascii, level); ascii.Append(ASCIIPropertyListParser.DICTIONARY_BEGIN_TOKEN); ascii.Append(NEWLINE); - foreach (string key in Keys) + foreach(string key in Keys) { NSObject val = ObjectForKey(key); Indent(ascii, level + 1); @@ -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,17 +488,18 @@ 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 - /// - /// Add the specified key and value. + /// Add the specified key and value. /// /// Key. /// Value. @@ -508,7 +510,7 @@ namespace Claunia.PropertyList } /// - /// Checks if there is any item contained in the current instance corresponding with the specified key. + /// Checks if there is any item contained in the current instance corresponding with the specified key. /// /// true, if key was contained, false otherwise. /// Key. @@ -518,7 +520,7 @@ namespace Claunia.PropertyList } /// - /// Checks if there is any item contained in the current instance corresponding with the specified value. + /// Checks if there is any item contained in the current instance corresponding with the specified value. /// /// true, if value is contained, false otherwise. /// Key. @@ -528,7 +530,7 @@ namespace Claunia.PropertyList } /// - /// Removes the item belonging to the specified key. + /// Removes the item belonging to the specified key. /// /// Key. public bool Remove(string key) @@ -538,7 +540,7 @@ namespace Claunia.PropertyList } /// - /// Tries to get the item corresponding to the specified key + /// Tries to get the item corresponding to the specified key /// /// true, if get value was successfully found and retrieved, false otherwise. /// Key. @@ -549,55 +551,36 @@ namespace Claunia.PropertyList } /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// Index. 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; } } /// - /// Gets an array with all the keys contained in the current instance. + /// Gets an array with all the keys contained in the current instance. /// /// The keys. - public ICollection Keys - { - get - { - return dict.Keys; - } - } + public ICollection Keys => dict.Keys; /// - /// Gets an array with all the objects contained in the current instance. + /// Gets an array with all the objects contained in the current instance. /// /// The objects. - public ICollection Values - { - get - { - return dict.Values; - } - } - + public ICollection Values => dict.Values; #endregion #region ICollection implementation /// - /// Adds the specified item. + /// Adds the specified item. /// /// Item. public void Add(KeyValuePair item) @@ -607,7 +590,7 @@ namespace Claunia.PropertyList } /// - /// Clears this instance. + /// Clears this instance. /// public void Clear() { @@ -616,7 +599,7 @@ namespace Claunia.PropertyList } /// - /// Checks if the current instance contains the specified item. + /// Checks if the current instance contains the specified item. /// /// Item. /// true if it is found, false otherwise. @@ -626,9 +609,13 @@ namespace Claunia.PropertyList } /// - /// Copies the elements to an existing one-dimensional , starting at the specified array index. + /// Copies the elements to an existing one-dimensional + /// , starting at the specified array index. /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// + /// The one-dimensional that is the destination of the elements copied from + /// . The must have zero-based indexing. + /// /// The zero-based index in array at which copying begins. public void CopyTo(KeyValuePair[] array, int arrayIndex) { @@ -637,7 +624,7 @@ namespace Claunia.PropertyList } /// - /// Removes the specified item. + /// Removes the specified item. /// /// Item to remove. /// true if successfully removed, false if not, or if item is not in current instance. @@ -648,51 +635,16 @@ namespace Claunia.PropertyList } /// - /// Gets the count of items in the current instance. + /// Gets the count of items in the current instance. /// /// How many items are contained in the current instance. - public int Count - { - get - { - return dict.Count; - } - } + public int Count => dict.Count; /// - /// Gets a value indicating whether this instance is read only. + /// Gets a value indicating whether this instance is read only. /// /// true if this instance is read only; otherwise, false. - public bool IsReadOnly - { - get - { - return false; - } - } - - #endregion - - #region IEnumerable implementation - /// - /// Gets the enumerator. - /// - /// The enumerator. - public IEnumerator> GetEnumerator() - { - return dict.GetEnumerator(); - } - - #endregion - - #region IEnumerable implementation - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return dict.GetEnumerator(); - } - + public bool IsReadOnly => false; #endregion } -} - +} \ No newline at end of file diff --git a/plist-cil/NSNumber.cs b/plist-cil/NSNumber.cs index f30a9d5..ed91a94 100644 --- a/plist-cil/NSNumber.cs +++ b/plist-cil/NSNumber.cs @@ -22,56 +22,57 @@ // 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 { /// - /// A number whose value is either an integer, a real number or bool. + /// A number whose value is either an integer, a real number or bool. /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public class NSNumber : NSObject, IComparable { /// - /// Indicates that the number's value is an integer. - /// The number is stored as a .NET . - /// Its original value could have been char, short, int, long or even long long. + /// Indicates that the number's value is an integer. + /// The number is stored as a .NET . + /// Its original value could have been char, short, int, long or even long long. /// public const int INTEGER = 0; /// - /// Indicates that the number's value is a real number. - /// The number is stored as a .NET . - /// Its original value could have been float or double. + /// Indicates that the number's value is a real number. + /// The number is stored as a .NET . + /// Its original value could have been float or double. /// public const int REAL = 1; /// - /// Indicates that the number's value is bool. + /// Indicates that the number's value is bool. /// 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; - /// - /// Parses integers and real numbers from their binary representation. - /// Note: real numbers are not yet supported. + /// Parses integers and real numbers from their binary representation. + /// Note: real numbers are not yet supported. /// /// The binary representation /// The type of number - /// - /// + /// + /// public NSNumber(ReadOnlySpan bytes, int type) { - switch (type) + switch(type) { case INTEGER: doubleValue = longValue = BinaryPropertyListParser.ParseLong(bytes); @@ -79,141 +80,168 @@ namespace Claunia.PropertyList case REAL: doubleValue = BinaryPropertyListParser.ParseDouble(bytes); - longValue = (long)Math.Round(doubleValue); + 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; } public NSNumber(string text, int type) { - switch (type) + switch(type) { case INTEGER: - { - doubleValue = longValue = long.Parse(text, CultureInfo.InvariantCulture); - break; - } + { + doubleValue = longValue = long.Parse(text, CultureInfo.InvariantCulture); + break; + } case REAL: - { - doubleValue = double.Parse(text, CultureInfo.InvariantCulture); - longValue = (long)Math.Round(doubleValue); - break; - } - default: - { - throw new ArgumentException("Type argument is not valid."); - } + { + doubleValue = double.Parse(text, CultureInfo.InvariantCulture); + longValue = (long)Math.Round(doubleValue); + break; + } + default: { throw new ArgumentException("Type argument is not valid."); } } + this.type = type; } /// - /// Creates a number from its textual representation. + /// Creates a number from its textual representation. /// /// The textual representation of the number. - /// - /// - /// + /// + /// + /// 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; + long l; double d; - if (text.StartsWith("0x") && long.TryParse("", NumberStyles.HexNumber, CultureInfo.InvariantCulture, out l)) + if(text.StartsWith("0x") && long.TryParse("", NumberStyles.HexNumber, CultureInfo.InvariantCulture, out l)) { doubleValue = longValue = l; - type = INTEGER; + type = INTEGER; } - if (long.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out l)) + + if(long.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out l)) { doubleValue = longValue = l; - type = INTEGER; + type = INTEGER; } - else if (double.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out d)) + else if(double.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out d)) { doubleValue = d; - longValue = (long)Math.Round(doubleValue); - type = REAL; + longValue = (long)Math.Round(doubleValue); + type = REAL; } 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) + if(isTrue || isFalse) { - type = BOOLEAN; + type = BOOLEAN; 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."); } } /// - /// Creates an integer number. + /// Creates an integer number. /// /// The integer value. public NSNumber(int i) { doubleValue = longValue = i; - type = INTEGER; + type = INTEGER; } /// - /// Creates an integer number. + /// Creates an integer number. /// /// The long integer value. public NSNumber(long l) { doubleValue = longValue = l; - type = INTEGER; + type = INTEGER; } /// - /// Creates a real number. + /// Creates a real number. /// /// The real value. public NSNumber(double d) { longValue = (long)(doubleValue = d); - type = REAL; + type = REAL; } /// - /// Creates a bool number. + /// Creates a bool number. /// /// The bool value. public NSNumber(bool b) { - boolValue = b; + boolValue = b; doubleValue = longValue = b ? 1 : 0; - type = BOOLEAN; + type = BOOLEAN; } /// - /// Gets the type of this number's value. + /// Compares the current to the specified object. + /// + /// + /// 0 if the numbers are equal, 1 if the current is greater + /// than the argument and -1 if it is less, or the argument is not a number. + /// + /// Object to compare to the current . + 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; + } + + /// + /// Gets the type of this number's value. /// /// The type flag. - /// - /// - /// + /// + /// + /// public int GetNSNumberType() { return type; } /// - /// Checks whether the value of this NSNumber is a bool. + /// Checks whether the value of this NSNumber is a bool. /// /// Whether the number's value is a bool. public bool isBoolean() @@ -222,7 +250,7 @@ namespace Claunia.PropertyList } /// - /// Checks whether the value of this NSNumber is an integer. + /// Checks whether the value of this NSNumber is an integer. /// /// Whether the number's value is an integer. public bool isInteger() @@ -231,7 +259,7 @@ namespace Claunia.PropertyList } /// - /// Checks whether the value of this NSNumber is a real number. + /// Checks whether the value of this NSNumber is a real number. /// /// Whether the number's value is a real number. public bool isReal() @@ -240,18 +268,18 @@ namespace Claunia.PropertyList } /// - /// The number's bool value. + /// The number's bool value. /// /// true if the value is true or non-zero, false otherwise. public bool ToBool() { - if (type == BOOLEAN) - return boolValue; + if(type == BOOLEAN) return boolValue; + return longValue != 0; } /// - /// The number's long value. + /// The number's long value. /// /// The value of the number as long public long ToLong() @@ -260,10 +288,12 @@ namespace Claunia.PropertyList } /// - /// The number's int value. - /// 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. + /// The number's int value. + /// + /// 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. + /// /// /// The value of the number as int. public int ToInt() @@ -272,7 +302,7 @@ namespace Claunia.PropertyList } /// - /// The number's double value. + /// The number's double value. /// /// The value of the number as double. public double ToDouble() @@ -281,8 +311,8 @@ namespace Claunia.PropertyList } /// - /// The number's float value. - /// WARNING: Possible loss of precision if the value is outside the float range. + /// The number's float value. + /// WARNING: Possible loss of precision if the value is outside the float range. /// /// The value of the number as float. public float floatValue() @@ -291,406 +321,329 @@ namespace Claunia.PropertyList } /// - /// Checks whether the other object is a NSNumber of the same value. + /// Checks whether the other object is a NSNumber of the same value. /// /// The object to compare to. /// Whether the objects are equal in terms of numeric value and type. - 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; } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a - /// hash table. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + /// 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; } /// - /// Returns a that represents the current . + /// Returns a that represents the current . /// - /// A that represents the current . + /// A that represents the current . public override string ToString() { - switch (type) + 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(); } } } internal override void ToXml(StringBuilder xml, int level) { Indent(xml, level); - switch (type) + switch(type) { case INTEGER: - { - xml.Append(""); - xml.Append(ToLong()); - xml.Append(""); - break; - } + { + xml.Append(""); + xml.Append(ToLong()); + xml.Append(""); + break; + } case REAL: - { - xml.Append(""); + { + xml.Append(""); - 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(""); - break; - } + xml.Append(""); + break; + } case BOOLEAN: - { - if (ToBool()) - xml.Append(""); - else - xml.Append(""); - break; - } + { + if(ToBool()) xml.Append(""); + else xml.Append(""); + break; + } } } internal override void ToBinary(BinaryPropertyListWriter outPlist) { - switch (GetNSNumberType()) + switch(GetNSNumberType()) { case INTEGER: + { + if(ToLong() < 0) { - if (ToLong() < 0) - { - outPlist.Write(0x13); - outPlist.WriteBytes(ToLong(), 8); - } - else if (ToLong() <= 0xff) - { - outPlist.Write(0x10); - outPlist.WriteBytes(ToLong(), 1); - } - else if (ToLong() <= 0xffff) - { - outPlist.Write(0x11); - outPlist.WriteBytes(ToLong(), 2); - } - else if (ToLong() <= 0xffffffffL) - { - outPlist.Write(0x12); - outPlist.WriteBytes(ToLong(), 4); - } - else - { - outPlist.Write(0x13); - outPlist.WriteBytes(ToLong(), 8); - } - break; + outPlist.Write(0x13); + outPlist.WriteBytes(ToLong(), 8); } + else if(ToLong() <= 0xff) + { + outPlist.Write(0x10); + outPlist.WriteBytes(ToLong(), 1); + } + else if(ToLong() <= 0xffff) + { + outPlist.Write(0x11); + outPlist.WriteBytes(ToLong(), 2); + } + else if(ToLong() <= 0xffffffffL) + { + outPlist.Write(0x12); + outPlist.WriteBytes(ToLong(), 4); + } + else + { + outPlist.Write(0x13); + outPlist.WriteBytes(ToLong(), 8); + } + + break; + } case REAL: - { - outPlist.Write(0x23); - outPlist.WriteDouble(ToDouble()); - break; - } + { + outPlist.Write(0x23); + outPlist.WriteDouble(ToDouble()); + break; + } case BOOLEAN: - { - outPlist.Write(ToBool() ? 0x09 : 0x08); - break; - } + { + outPlist.Write(ToBool() ? 0x09 : 0x08); + break; + } } } 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) { Indent(ascii, level); - switch (type) + switch(type) { case INTEGER: - { - ascii.Append("<*I"); - ascii.Append(ToString()); - ascii.Append(">"); - break; - } + { + ascii.Append("<*I"); + ascii.Append(ToString()); + ascii.Append(">"); + break; + } case REAL: - { - ascii.Append("<*R"); - ascii.Append(ToString()); - ascii.Append(">"); - break; - } + { + ascii.Append("<*R"); + ascii.Append(ToString()); + ascii.Append(">"); + break; + } case BOOLEAN: - { - if (boolValue) - { - ascii.Append("<*BY>"); - } - else - { - ascii.Append("<*BN>"); - } - break; - } + { + if(boolValue) ascii.Append("<*BY>"); + else ascii.Append("<*BN>"); + break; + } } } /// - /// Compares the current to the specified object. - /// - /// 0 if the numbers are equal, 1 if the current is greater - /// than the argument and -1 if it is less, or the argument is not a number. - /// Object to compare to the current . - 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; - } - - /// - /// Determines if an object is a number. - /// Substitutes .NET's Number class comparison + /// Determines if an object is a number. + /// Substitutes .NET's Number class comparison /// /// true if it is a number. /// Object. - 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; } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// 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) + 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); } } -} - +} \ No newline at end of file diff --git a/plist-cil/NSObject.cs b/plist-cil/NSObject.cs index daaa42c..a2c6b54 100644 --- a/plist-cil/NSObject.cs +++ b/plist-cil/NSObject.cs @@ -22,56 +22,56 @@ // 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; namespace Claunia.PropertyList { /// - /// - /// Abstract interface for any object contained in a property list. - /// - /// The names and functions of the various objects orient themselves - /// towards Apple's Cocoa API. - /// + /// + /// Abstract interface for any object contained in a property list. + /// + /// + /// The names and functions of the various objects orient themselves + /// towards Apple's Cocoa API. + /// /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public abstract class NSObject { /// - /// The newline character used for generating the XML output. - /// To maintain compatibility with the Apple format, only a newline character - /// is used (as opposed to cr+lf which is normally used on Windows). + /// The newline character used for generating the XML output. + /// To maintain compatibility with the Apple format, only a newline character + /// is used (as opposed to cr+lf which is normally used on Windows). /// - readonly internal static string NEWLINE = "\n"; - + internal static readonly string NEWLINE = "\n"; /// - /// The identation character used for generating the XML output. This is the - /// tabulator character. + /// The identation character used for generating the XML output. This is the + /// tabulator character. /// - readonly static string INDENT = "\t"; + static readonly string INDENT = "\t"; /// - /// 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. + /// 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. /// - internal readonly static int ASCII_LINE_LENGTH = 80; + internal static readonly int ASCII_LINE_LENGTH = 80; /// - /// Generates the XML representation of the object (without XML headers or enclosing plist-tags). + /// Generates the XML representation of the object (without XML headers or enclosing plist-tags). /// /// The StringBuilder onto which the XML representation is appended. /// The indentation level of the object. internal abstract void ToXml(StringBuilder xml, int level); /// - /// Assigns IDs to all the objects in this NSObject subtree. + /// Assigns IDs to all the objects in this NSObject subtree. /// /// The writer object that handles the binary serialization. internal virtual void AssignIDs(BinaryPropertyListWriter outPlist) @@ -80,62 +80,62 @@ namespace Claunia.PropertyList } /// - /// Generates the binary representation of the object. + /// Generates the binary representation of the object. /// /// The output stream to serialize the object to. internal abstract void ToBinary(BinaryPropertyListWriter outPlist); /// - /// Generates a valid XML property list including headers using this object as root. + /// Generates a valid XML property list including headers using this object as root. /// /// The XML representation of the property list including XML header and doctype information. public string ToXmlPropertyList() { StringBuilder xml = new StringBuilder(""); - xml.Append(NSObject.NEWLINE); + xml.Append(NEWLINE); xml.Append(""); - xml.Append(NSObject.NEWLINE); + xml.Append(NEWLINE); xml.Append(""); - xml.Append(NSObject.NEWLINE); + xml.Append(NEWLINE); ToXml(xml, 0); - xml.Append(NSObject.NEWLINE); + xml.Append(NEWLINE); xml.Append(""); - xml.Append(NSObject.NEWLINE); + xml.Append(NEWLINE); return xml.ToString(); } /// - /// 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 + /// 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 /// /// The StringBuilder onto which the ASCII representation is appended. /// The indentation level of the object. internal abstract void ToASCII(StringBuilder ascii, int level); /// - /// Generates the ASCII representation of this object in the GnuStep format. - /// The generated ASCII representation does not end with a newline. + /// Generates the ASCII representation of this object in the GnuStep format. + /// The generated ASCII representation does not end with a newline. /// /// The StringBuilder onto which the ASCII representation is appended. /// The indentation level of the object. internal abstract void ToASCIIGnuStep(StringBuilder ascii, int level); /// - /// Helper method that adds correct identation to the xml output. - /// Calling this method will add level number of tab characters - /// to the xml string. + /// Helper method that adds correct identation to the xml output. + /// Calling this method will add level number of tab characters + /// to the xml string. /// /// The string builder for the XML document. /// The level of identation. 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); } /// - /// Wraps the given value inside a NSObject. + /// Wraps the given value inside a NSObject. /// /// The value to represent as a NSObject. /// A NSObject representing the given value. @@ -145,7 +145,7 @@ namespace Claunia.PropertyList } /// - /// Wraps the given value inside a NSObject. + /// Wraps the given value inside a NSObject. /// /// The value to represent as a NSObject. /// A NSObject representing the given value. @@ -155,7 +155,7 @@ namespace Claunia.PropertyList } /// - /// Wraps the given value inside a NSObject. + /// Wraps the given value inside a NSObject. /// /// The value to represent as a NSObject. /// A NSObject representing the given value. @@ -165,7 +165,7 @@ namespace Claunia.PropertyList } /// - /// Wraps the given value inside a NSObject. + /// Wraps the given value inside a NSObject. /// /// The value to represent as a NSObject. /// A NSObject representing the given value. @@ -175,305 +175,279 @@ namespace Claunia.PropertyList } /// - /// Creates a NSArray with the contents of the given array. + /// Creates a NSArray with the contents of the given array. /// /// The value to represent as a NSObject. /// A NSObject representing the given value. /// When one of the objects contained in the array cannot be represented by a NSObject. - 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; } /// - /// Creates a NSDictionary with the contents of the given map. + /// Creates a NSDictionary with the contents of the given map. /// /// The value to represent as a NSObject. /// A NSObject representing the given value. /// When one of the values contained in the map cannot be represented by a NSObject. - public static NSDictionary Wrap(Dictionary value) + public static NSDictionary Wrap(Dictionary value) { NSDictionary dict = new NSDictionary(); - foreach (KeyValuePair kvp in value) - dict.Add(kvp.Key, Wrap(kvp.Value)); + foreach(KeyValuePair kvp in value) dict.Add(kvp.Key, Wrap(kvp.Value)); return dict; } /// - /// Creates a NSSet with the contents of this set. + /// Creates a NSSet with the contents of this set. /// /// The value to represent as a NSObject. /// A NSObject representing the given value. /// When one of the values contained in the map cannot be represented by a NSObject. - public static NSSet Wrap(List value) + public static NSSet Wrap(List 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; } /// - /// - /// Creates a NSObject representing the given .NET Object. - /// - /// Numerics of type , , , , , or are wrapped as NSNumber objects. - /// - /// Strings are wrapped as objects and byte arrays as objects. - /// - /// DateTime objects are wrapped as objects. - /// - /// Serializable classes are serialized and their data is stored in objects. - /// - /// Arrays and Collection objects are converted to where each array member is wrapped into a . - /// - /// Dictionaries are converted to . Each key is converted to a string and each value wrapped into a . - /// + /// + /// Creates a NSObject representing the given .NET Object. + /// + /// + /// Numerics of type , , , , + /// , or are wrapped as NSNumber objects. + /// + /// + /// Strings are wrapped as objects and byte arrays as objects. + /// + /// + /// DateTime objects are wrapped as objects. + /// + /// + /// Serializable classes are serialized and their data is stored in objects. + /// + /// + /// Arrays and Collection objects are converted to where each array member is wrapped into a + /// . + /// + /// + /// Dictionaries are converted to . Each key is converted to a string and each value + /// wrapped into a . + /// /// /// The object to represent. - ///A NSObject equivalent to the given object. - public static NSObject Wrap(Object o) + /// A NSObject equivalent to the given object. + 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 (c.IsArray) + 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))) + if(cc.Equals(typeof(byte))) return Wrap((byte[])o); + + if(cc.Equals(typeof(bool))) { - 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])); + bool[] array = (bool[])o; + NSArray nsa = new NSArray(array.Length); + for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i])); return nsa; } - if (cc.Equals(typeof(float))) + + 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])); + NSArray nsa = new NSArray(array.Length); + for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i])); return nsa; } - if (cc.Equals(typeof(double))) + + 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])); + NSArray nsa = new NSArray(array.Length); + for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i])); return nsa; } - if (cc.Equals(typeof(short))) + + 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])); + NSArray nsa = new NSArray(array.Length); + for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i])); return nsa; } - if (cc.Equals(typeof(int))) + + 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])); + int[] array = (int[])o; + NSArray nsa = new NSArray(array.Length); + for(int i = 0; i < array.Length; i++) nsa.Add(Wrap(array[i])); return nsa; } - if (cc.Equals(typeof(long))) + + 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])); + long[] array = (long[])o; + NSArray nsa = new NSArray(array.Length); + 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).IsAssignableFrom(c)) + + if(typeof(Dictionary).IsAssignableFrom(c)) { - Dictionary netDict = (Dictionary)o; - NSDictionary dict = new NSDictionary(); - foreach (KeyValuePair kvp in netDict) - { - dict.Add(kvp.Key, Wrap(kvp.Value)); - } + Dictionary netDict = (Dictionary)o; + NSDictionary dict = new NSDictionary(); + foreach(KeyValuePair kvp in netDict) dict.Add(kvp.Key, Wrap(kvp.Value)); return dict; } - if (typeof(List).IsAssignableFrom(c)) - return Wrap(((List)o).ToArray()); + + if(typeof(List).IsAssignableFrom(c)) return Wrap(((List)o).ToArray()); throw new PropertyListException(string.Format("Cannot wrap an object of type {0}.", o.GetType().Name)); } /// - /// Converts this NSObject into an equivalent object - /// of the .NET Runtime Environment. - /// objects are converted to arrays. - /// objects are converted to objects extending the class. - /// objects are converted to objects extending the class. - /// objects are converted to primitive number values (, , or ). - /// objects are converted to objects. - /// objects are converted to arrays. - /// objects are converted to objects. - /// objects are converted to arrays. + /// Converts this NSObject into an equivalent object + /// of the .NET Runtime Environment. + /// objects are converted to arrays. + /// + /// objects are converted to objects extending the + /// class. + /// + /// objects are converted to objects extending the class. + /// + /// objects are converted to primitive number values (, + /// , or ). + /// + /// objects are converted to objects. + /// objects are converted to arrays. + /// objects are converted to objects. + /// objects are converted to arrays. /// /// A native .NET object representing this NSObject's value. - public Object ToObject() + public object ToObject() { - if (this is NSArray) + if(this is NSArray) { - var nsArray = (NSArray)this; - object[] array = new object[nsArray.Count]; - for (int i = 0; i < nsArray.Count; i++) - { - array[i] = nsArray[i].ToObject(); - } + NSArray nsArray = (NSArray)this; + object[] array = new object[nsArray.Count]; + for(int i = 0; i < nsArray.Count; i++) array[i] = nsArray[i].ToObject(); return array; } - if (this is NSDictionary) + + if(this is NSDictionary) { Dictionary dictA = ((NSDictionary)this).GetDictionary(); - Dictionary dictB = new Dictionary(dictA.Count); - foreach (KeyValuePair kvp in dictA) - { - dictB.Add(kvp.Key, kvp.Value.ToObject()); - } + Dictionary dictB = new Dictionary(dictA.Count); + foreach(KeyValuePair kvp in dictA) dictB.Add(kvp.Key, kvp.Value.ToObject()); return dictB; } - if (this is NSSet) + + if(this is NSSet) { List setA = ((NSSet)this).GetSet(); - List setB = new List(); - foreach (NSObject o in setA) - { - setB.Add(o.ToObject()); - } + List setB = new List(); + foreach(NSObject o in setA) setB.Add(o.ToObject()); return setB; } - if (this is NSNumber) + + if(this is NSNumber) { NSNumber num = (NSNumber)this; - switch (num.GetNSNumberType()) + switch(num.GetNSNumberType()) { case NSNumber.INTEGER: - { - long longVal = num.ToLong(); - 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(); + { + long longVal = num.ToLong(); + 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(); } } - 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; + + 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; } internal static bool ArrayEquals(byte[] arrayA, byte[] arrayB) { - if (arrayA.Length == arrayB.Length) + if(arrayA.Length == arrayB.Length) { - for (int i = 0; i < arrayA.Length; i++) - if (arrayA[i] != arrayB[i]) + for(int i = 0; i < arrayA.Length; i++) + if(arrayA[i] != arrayB[i]) return false; + return true; } + return false; } internal static bool ArrayEquals(IList arrayA, IList arrayB) { - if (arrayA.Count == arrayB.Count) + if(arrayA.Count == arrayB.Count) { - for (int i = 0; i < arrayA.Count; i++) - { - if (arrayA[i] != arrayB[i]) - { + for(int i = 0; i < arrayA.Count; i++) + if(arrayA[i] != arrayB[i]) return false; - } - } + return true; } + return false; } /// - /// Determines if the specific NSObject is the same as the NSObject overriding this method. + /// Determines if the specific NSObject is the same as the NSObject overriding this method. /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// public abstract bool Equals(NSObject obj); } -} - +} \ No newline at end of file diff --git a/plist-cil/NSSet.cs b/plist-cil/NSSet.cs index fb56287..146b7cb 100644 --- a/plist-cil/NSSet.cs +++ b/plist-cil/NSSet.cs @@ -22,20 +22,22 @@ // 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 { /// - /// - /// A set is an interface to an unordered collection of objects. - /// - /// This implementation uses a as the underlying - /// data structure. - /// + /// + /// A set is an interface to an unordered collection of objects. + /// + /// + /// This implementation uses a as the underlying + /// data structure. + /// /// /// @author Daniel Dreibrodt /// @author Natalia Portillo @@ -46,7 +48,7 @@ namespace Claunia.PropertyList bool ordered; /// - /// Creates an empty unordered set. + /// Creates an empty unordered set. /// public NSSet() { @@ -54,18 +56,17 @@ namespace Claunia.PropertyList } /// - /// Creates an empty set. + /// Creates an empty set. /// /// Should the set be ordered on operations? public NSSet(bool ordered) { this.ordered = ordered; - set = new List(); + set = new List(); } - /// - /// Creates a set and fill it with the given objects. + /// Creates a set and fill it with the given objects. /// /// The objects to populate the set. public NSSet(params NSObject[] objects) @@ -74,73 +75,87 @@ namespace Claunia.PropertyList } /// - /// Creates a set and fill it with the given objects. + /// Creates a set and fill it with the given objects. /// /// The objects to populate the set. /// Should the set be ordered on operations? public NSSet(bool ordered, params NSObject[] objects) { this.ordered = ordered; - set = new List(objects); - if (ordered) - set.Sort(); + set = new List(objects); + if(ordered) set.Sort(); } /// - /// Adds an object to the set. + /// Gets the number of elements in the set. + /// + /// The number of elements in the set. + public int Count + { + get + { + lock(set) return set.Count; + } + } + + /// + /// Returns an enumerator object that lets you iterate over all elements of the set. + /// This is the equivalent to objectEnumerator in the Cocoa implementation + /// of NSSet. + /// + /// The iterator for the set. + public IEnumerator GetEnumerator() + { + lock(set) return set.GetEnumerator(); + } + + /// + /// Adds an object to the set. /// /// The object to add. public void AddObject(NSObject obj) { - lock (set) + lock(set) { set.Add(obj); - if (ordered) - set.Sort(); + if(ordered) set.Sort(); } } /// - /// Removes an object from the set. + /// Removes an object from the set. /// /// The object to remove. public void RemoveObject(NSObject obj) { - lock (set) + lock(set) { set.Remove(obj); - if (ordered) - set.Sort(); + if(ordered) set.Sort(); } } /// - /// Returns all objects contained in the set. + /// Returns all objects contained in the set. /// /// An array of all objects in the set. public NSObject[] AllObjects() { - lock (set) - { - return set.ToArray(); - } + lock(set) return set.ToArray(); } /// - /// Returns one of the objects in the set, or null - /// if the set contains no objects. + /// Returns one of the objects in the set, or null + /// if the set contains no objects. /// /// The first object in the set, or null if the set is empty. public NSObject AnyObject() { - lock (set) - { - return set.Count == 0 ? null : set[0]; - } + lock(set) return set.Count == 0 ? null : set[0]; } /// - /// Finds out whether a given object is contained in the set. + /// Finds out whether a given object is contained in the set. /// /// true, when the object was found, false otherwise. /// The object to look for. @@ -150,76 +165,59 @@ namespace Claunia.PropertyList } /// - /// Determines whether the set contains an object equal to a given object - /// and returns that object if it is present. + /// Determines whether the set contains an object equal to a given object + /// and returns that object if it is present. /// /// The object to look for. /// The object if it is present, null otherwise. public NSObject Member(NSObject obj) { - lock (set) + lock(set) { - foreach (NSObject o in set) - { - if (o.Equals(obj)) + foreach(NSObject o in set) + if(o.Equals(obj)) return o; - } + return null; } } /// - /// Finds out whether at least one object is present in both sets. + /// Finds out whether at least one object is present in both sets. /// /// true if the intersection of both sets is empty, false otherwise. /// The other set. public bool IntersectsSet(NSSet otherSet) { - lock (set) + lock(set) { - foreach (NSObject o in set) - { - if (otherSet.ContainsObject(o)) + foreach(NSObject o in set) + if(otherSet.ContainsObject(o)) return true; - } + return false; } } /// - /// Finds out if this set is a subset of the given set. + /// Finds out if this set is a subset of the given set. /// /// true if all elements in this set are also present in the other set, falseotherwise. /// The other set. public bool IsSubsetOfSet(NSSet otherSet) { - lock (set) + lock(set) { - foreach (NSObject o in set) - { - if (!otherSet.ContainsObject(o)) + foreach(NSObject o in set) + if(!otherSet.ContainsObject(o)) return false; - } + return true; } } /// - /// Returns an enumerator object that lets you iterate over all elements of the set. - /// This is the equivalent to objectEnumerator in the Cocoa implementation - /// of NSSet. - /// - /// The iterator for the set. - public IEnumerator GetEnumerator() - { - lock (set) - { - return set.GetEnumerator(); - } - } - - /// - /// Gets the underlying data structure in which this NSSets stores its content. + /// Gets the underlying data structure in which this NSSets stores its content. /// /// A Set object. internal List GetSet() @@ -228,10 +226,12 @@ namespace Claunia.PropertyList } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a - /// hash table. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + /// public override int GetHashCode() { int hash = 7; @@ -240,44 +240,31 @@ namespace Claunia.PropertyList } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals(Object obj) + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// + 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))); } /// - /// Gets the number of elements in the set. - /// - /// The number of elements in the set. - public int Count - { - get - { - lock (set) - { - return set.Count; - } - } - } - - /// - /// Returns the XML representantion for this set. - /// There is no official XML representation specified for sets. - /// In this implementation it is represented by an array. + /// Returns the XML representantion for this set. + /// There is no official XML representation specified for sets. + /// In this implementation it is represented by an array. /// /// The XML StringBuilder /// The indentation level @@ -285,14 +272,14 @@ namespace Claunia.PropertyList { Indent(xml, level); xml.Append(""); - xml.Append(NSObject.NEWLINE); - if (ordered) - set.Sort(); - foreach (NSObject o in set) + 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(""); } @@ -300,49 +287,40 @@ 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) { - if (ordered) + if(ordered) { 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)); } /// - /// Returns the ASCII representation of this set. - /// There is no official ASCII representation for sets. - /// In this implementation sets are represented as arrays. + /// Returns the ASCII representation of this set. + /// There is no official ASCII representation for sets. + /// In this implementation sets are represented as arrays. /// /// The ASCII file string builder /// The indentation level 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++) + 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,43 +328,41 @@ 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) + if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) { ascii.Append(NEWLINE); indexOfLastNewLine = ascii.Length; } } + ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN); } /// - /// Returns the ASCII representation of this set according to the GnuStep format. - /// There is no official ASCII representation for sets. - /// In this implementation sets are represented as arrays. + /// Returns the ASCII representation of this set according to the GnuStep format. + /// There is no official ASCII representation for sets. + /// In this implementation sets are represented as arrays. /// /// The ASCII file string builder /// The indentation level 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++) + 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,43 +370,45 @@ 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) + if(ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) { ascii.Append(NEWLINE); indexOfLastNewLine = ascii.Length; } } + ascii.Append(ASCIIPropertyListParser.ARRAY_END_TOKEN); } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// 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)) + foreach(NSObject objS in (NSSet)obj) + if(!set.Contains(objS)) return false; return true; } } -} - +} \ No newline at end of file diff --git a/plist-cil/NSString.cs b/plist-cil/NSString.cs index fd5003d..236b934 100644 --- a/plist-cil/NSString.cs +++ b/plist-cil/NSString.cs @@ -22,67 +22,74 @@ // 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; namespace Claunia.PropertyList { /// - /// A NSString contains a string. + /// A NSString contains a string. /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public class NSString : NSObject, IComparable { - string content; + static Encoding asciiEncoder, utf16beEncoder, utf8Encoder; /// - /// Creates a NSString from its binary representation. + /// Creates a NSString from its binary representation. /// /// The binary representation. /// The encoding of the binary representation, the name of a supported charset. /// The encoding charset is invalid or not supported by the underlying platform. - public NSString(ReadOnlySpan bytes, String encoding) - : this(bytes, Encoding.GetEncoding(encoding)) - { - } + public NSString(ReadOnlySpan bytes, string encoding) : this(bytes, Encoding.GetEncoding(encoding)) { } /// - /// Creates a NSString from its binary representation. + /// Creates a NSString from its binary representation. /// /// The binary representation. /// The encoding of the binary representation. /// The encoding charset is invalid or not supported by the underlying platform. public NSString(ReadOnlySpan bytes, Encoding encoding) { -#if NATIVE_SPAN - content = encoding.GetString(bytes); -#else - content = encoding.GetString(bytes.ToArray()); -#endif + #if NATIVE_SPAN + Content = encoding.GetString(bytes); + #else + Content = encoding.GetString(bytes.ToArray()); + #endif } /// - /// Creates a NSString from a string. + /// Creates a NSString from a string. /// /// The string that will be contained in the NSString. public NSString(string text) { - content = text; + Content = text; } /// - /// Gets this strings content. + /// Gets this strings content. /// /// This NSString as .NET string object. - public string Content + public string Content { get; set; } + + /// + /// Compares the current to the specified object. + /// + /// A 32-bit signed integer that indicates the lexical relationship between the two comparands. + /// Object to compare to the current . + 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; } /// - /// Appends a string to this string. + /// Appends a string to this string. /// /// The string to append. public void Append(NSString s) @@ -91,25 +98,25 @@ namespace Claunia.PropertyList } /// - /// Appends a string to this string. + /// Appends a string to this string. /// /// The string to append. public void Append(string s) { - content += s; + Content += s; } /// - /// Prepends a string to this string. + /// Prepends a string to this string. /// /// The string to prepend. public void Prepend(string s) { - content = s + content; + Content = s + Content; } /// - /// Prepends a string to this string. + /// Prepends a string to this string. /// /// The string to prepend. public void Prepend(NSString s) @@ -118,56 +125,61 @@ namespace Claunia.PropertyList } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals(Object obj) + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// + 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); } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a - /// hash table. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + /// public override int GetHashCode() { - return content.GetHashCode(); + return Content.GetHashCode(); } /// - /// The textual representation of this NSString. + /// The textual representation of this NSString. /// /// The NSString's contents. public override string ToString() { - return content; + return Content; } - static Encoding asciiEncoder, utf16beEncoder, utf8Encoder; - internal override void ToXml(StringBuilder xml, int level) { Indent(xml, level); xml.Append(""); //Make sure that the string is encoded in UTF-8 for the XML output - lock (typeof(NSString)) + 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) + catch(Exception ex) { throw new PropertyListException("Could not encode the NSString into UTF-8: " + ex.Message); } @@ -175,44 +187,43 @@ 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("", "]]]]>")); + xml.Append(Content.Replace("]]>", "]]]]>")); xml.Append("]]>"); } - else - { - xml.Append(content); - } + else xml.Append(Content); + xml.Append(""); } internal override void ToBinary(BinaryPropertyListWriter outPlist) { - int kind; + int kind; byte[] byteBuf; - lock (typeof(NSString)) + lock(typeof(NSString)) { - if (asciiEncoder == null) + 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); + kind = 0x5; // standard ASCII + 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); + kind = 0x6; // UTF-16-BE + 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,107 +243,75 @@ namespace Claunia.PropertyList { Indent(ascii, level); ascii.Append("\""); - ascii.Append(EscapeStringForASCII(content)); + ascii.Append(EscapeStringForASCII(Content)); ascii.Append("\""); } /// - /// Escapes a string for use in ASCII property lists. + /// Escapes a string for use in ASCII property lists. /// /// The unescaped string. /// S. internal static string EscapeStringForASCII(string s) { string outString = ""; - char[] cArray = s.ToCharArray(); - foreach (char c in cArray) - { - if (c > 127) + 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; } /// - /// Compares the current to the specified object. + /// Determines whether the specified is equal to the current + /// . /// - /// A 32-bit signed integer that indicates the lexical relationship between the two comparands. - /// Object to compare to the current . - 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; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// 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) + foreach(char c in text) + 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); } } -} - +} \ No newline at end of file diff --git a/plist-cil/PropertyListException.cs b/plist-cil/PropertyListException.cs index 75085d5..61b1a17 100644 --- a/plist-cil/PropertyListException.cs +++ b/plist-cil/PropertyListException.cs @@ -23,55 +23,47 @@ // 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 { /// - /// The exception that is thrown when an property list file could not be processed correctly. + /// The exception that is thrown when an property list file could not be processed correctly. /// [Serializable] public class PropertyListException : Exception { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public PropertyListException() - { - } + public PropertyListException() { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// - /// The error message that explains the reason for the exception. + /// The error message that explains the reason for the exception. /// - public PropertyListException(string message) - : base(message) - { - } + public PropertyListException(string message) : base(message) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// - /// The error message that explains the reason for the exception. + /// The error message that explains the reason for the exception. /// /// - /// The exception that is the cause of the current exception, or - /// if no inner exception is specified. + /// The exception that is the cause of the current exception, or + /// if no inner exception is specified. /// - public PropertyListException(string message, Exception inner) - : base(message, inner) - { - } + public PropertyListException(string message, Exception inner) : base(message, inner) { } -#if !NETCORE + #if !NETCORE protected PropertyListException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endif } -} +} \ No newline at end of file diff --git a/plist-cil/PropertyListFormatException.cs b/plist-cil/PropertyListFormatException.cs index c7377d7..1b19857 100644 --- a/plist-cil/PropertyListFormatException.cs +++ b/plist-cil/PropertyListFormatException.cs @@ -22,25 +22,21 @@ // 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 { /// - /// A PropertyListFormatException is thrown by the various property list format parsers - /// when an error in the format of the given property list is encountered. + /// A PropertyListFormatException is thrown by the various property list format parsers + /// when an error in the format of the given property list is encountered. /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public class PropertyListFormatException : PropertyListException { /// - /// Creates a new exception with the given message. + /// Creates a new exception with the given message. /// /// A message containing information about the nature of the exception. - public PropertyListFormatException(string message) : base(message) - { - } + public PropertyListFormatException(string message) : base(message) { } } -} - +} \ No newline at end of file diff --git a/plist-cil/PropertyListParser.cs b/plist-cil/PropertyListParser.cs index bfce752..729d1a8 100644 --- a/plist-cil/PropertyListParser.cs +++ b/plist-cil/PropertyListParser.cs @@ -22,106 +22,85 @@ // 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 { /// - /// 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. + /// This class provides methods to parse property lists. It can handle files, + /// input streams and byte arrays. All known property list formats are supported. + /// This class also provides methods to save and convert property lists. /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public static class PropertyListParser { - const int TYPE_XML = 0; - const int TYPE_BINARY = 1; - const int TYPE_ASCII = 2; - const int TYPE_ERROR_BLANK = 10; + const int TYPE_XML = 0; + const int TYPE_BINARY = 1; + const int TYPE_ASCII = 2; + const int TYPE_ERROR_BLANK = 10; const int TYPE_ERROR_UNKNOWN = 11; /// - /// Determines the type of a property list by means of the first bytes of its data + /// Determines the type of a property list by means of the first bytes of its data /// /// The type of the property list /// The very first bytes of data of the property list (minus any whitespace) as a string static int DetermineTypeExact(ReadOnlySpan 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 - { - return TYPE_ERROR_UNKNOWN; - } + 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; } /// - /// Determines the type of a property list by means of the first bytes of its data + /// Determines the type of a property list by means of the first bytes of its data /// /// The very first bytes of data of the property list (minus any whitespace) /// The type of the property list static int DetermineType(ReadOnlySpan 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 header = bytes.Slice(offset, Math.Min(8, bytes.Length - offset)); return DetermineTypeExact(header); } /// - /// Determines the type of a property list by means of the first bytes of its data + /// Determines the type of a property list by means of the first bytes of its data /// /// The type of the property list - /// 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. + /// + /// 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. + /// 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 index = offset; long readLimit = index + 1024; - long mark = readLimit; + long mark = readLimit; fs.Seek(offset, SeekOrigin.Current); - int b; + int b; bool bom = false; //Skip any possible whitespace at the beginning of the file @@ -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; @@ -152,13 +132,13 @@ namespace Claunia.PropertyList } /// - /// Reads all bytes from an Stream and stores them in an array, up to - /// a maximum count. + /// Reads all bytes from an Stream and stores them in an array, up to + /// a maximum count. /// /// The Stream pointing to the data that should be stored in the array. internal static byte[] ReadAll(Stream fs) { - using (MemoryStream outputStream = new MemoryStream()) + using(MemoryStream outputStream = new MemoryStream()) { fs.CopyTo(outputStream); return outputStream.ToArray(); @@ -166,7 +146,7 @@ namespace Claunia.PropertyList } /// - /// Parses a property list from a file. + /// Parses a property list from a file. /// /// Path to the property list file. /// The root object in the property list. This is usually a NSDictionary but can also be a NSArray. @@ -176,40 +156,35 @@ namespace Claunia.PropertyList } /// - /// Parses a property list from a file. + /// Parses a property list from a file. /// /// The property list file. /// The root object in the property list. This is usually a NSDictionary but can also be a NSArray. public static NSObject Parse(FileInfo f) { - using (FileStream fis = f.OpenRead()) - { - return Parse(fis); - } + using(FileStream fis = f.OpenRead()) return Parse(fis); } /// - /// Parses a property list from a byte array. + /// Parses a property list from a byte array. /// /// The property list data as a byte array. /// The root object in the property list. This is usually a NSDictionary but can also be a NSArray. public static NSObject Parse(byte[] bytes) { - switch (DetermineType(bytes)) + 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."); } } /// - /// Parses a property list from a byte array. + /// Parses a property list from a byte array. /// /// The property list data as a byte array. /// The length of the property list. @@ -221,27 +196,25 @@ namespace Claunia.PropertyList } /// - /// Parses a property list from a byte span. + /// Parses a property list from a byte span. /// /// The property list data as a byte array. /// The root object in the property list. This is usually a NSDictionary but can also be a NSArray. public static NSObject Parse(ReadOnlySpan bytes) { - switch (DetermineType(bytes)) + 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."); } } /// - /// Parses a property list from an Stream. + /// Parses a property list from an Stream. /// /// The Stream delivering the property list data. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -251,7 +224,7 @@ namespace Claunia.PropertyList } /// - /// Saves a property list with the given object as root into a XML file. + /// Saves a property list with the given object as root into a XML file. /// /// The root object. /// The output file. @@ -259,41 +232,35 @@ 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); } /// - /// Saves a property list with the given object as root in XML format into an output stream. + /// Saves a property list with the given object as root in XML format into an output stream. /// /// The root object. /// The output stream. /// When an error occurs during the writing process. public static void SaveAsXml(NSObject root, Stream outStream) { -#if NET40 + #if NET40 // The StreamWriter constructor which takes a "leaveOpen" parameter is // not available on .NET 4.0 StreamWriter w = new StreamWriter(outStream, Encoding.UTF8); 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 + #endif } /// - /// Converts a given property list file into the OS X and iOS XML format. + /// Converts a given property list file into the OS X and iOS XML format. /// /// The source file. /// The target file. @@ -304,7 +271,7 @@ namespace Claunia.PropertyList } /// - /// Saves a property list with the given object as root into a binary file. + /// Saves a property list with the given object as root into a binary file. /// /// The root object. /// The output file. @@ -312,13 +279,12 @@ 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); } /// - /// Saves a property list with the given object as root in binary format into an output stream. + /// Saves a property list with the given object as root in binary format into an output stream. /// /// The root object. /// The output stream. @@ -329,7 +295,7 @@ namespace Claunia.PropertyList } /// - /// Converts a given property list file into the OS X and iOS binary format. + /// Converts a given property list file into the OS X and iOS binary format. /// /// The source file. /// The target file. @@ -340,7 +306,7 @@ namespace Claunia.PropertyList } /// - /// Saves a property list with the given object as root into a ASCII file. + /// Saves a property list with the given object as root into a ASCII file. /// /// The root object. /// The output file. @@ -348,17 +314,14 @@ namespace Claunia.PropertyList public static void SaveAsASCII(NSDictionary root, FileInfo outFile) { string parent = outFile.DirectoryName; - 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()); - } + 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()); } /// - /// Saves a property list with the given object as root into a ASCII file. + /// Saves a property list with the given object as root into a ASCII file. /// /// The root object. /// The output file. @@ -366,40 +329,29 @@ namespace Claunia.PropertyList public static void SaveAsASCII(NSArray root, FileInfo outFile) { string parent = outFile.DirectoryName; - 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()); - } + 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()); } /// - /// Converts a given property list file into ASCII format. + /// Converts a given property list file into ASCII format. /// /// The source file. /// The target file. 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!"); } /// - /// Saves a property list with the given object as root into a GnuStep ASCII file. + /// Saves a property list with the given object as root into a GnuStep ASCII file. /// /// The root object. /// The output file. @@ -407,17 +359,14 @@ namespace Claunia.PropertyList public static void SaveAsGnuStepASCII(NSDictionary root, FileInfo outFile) { string parent = outFile.DirectoryName; - 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()); - } + 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()); } /// - /// Saves a property list with the given object as root into a GnuStep ASCII file. + /// Saves a property list with the given object as root into a GnuStep ASCII file. /// /// The root object. /// The output file. @@ -425,37 +374,25 @@ namespace Claunia.PropertyList public static void SaveAsGnuStepASCII(NSArray root, FileInfo outFile) { string parent = outFile.DirectoryName; - 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()); - } + 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()); } /// - /// Converts a given property list file into GnuStep ASCII format. + /// Converts a given property list file into GnuStep ASCII format. /// /// The source file. /// The target file. 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!"); } } -} - +} \ No newline at end of file diff --git a/plist-cil/UID.cs b/plist-cil/UID.cs index 3dd1a8e..cf21b5c 100644 --- a/plist-cil/UID.cs +++ b/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; @@ -29,7 +30,7 @@ using System.Text; namespace Claunia.PropertyList { /// - /// An UID. Only found in binary property lists that are keyed archives. + /// An UID. Only found in binary property lists that are keyed archives. /// /// @author Daniel Dreibrodt /// @author Natalia Portillo @@ -38,241 +39,226 @@ namespace Claunia.PropertyList readonly ulong value; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Name. /// Bytes. [Obsolete("UIDs have not meaningful names")] - public UID(String name, ReadOnlySpan bytes) + public UID(string name, ReadOnlySpan bytes) { - if (bytes.Length != 1 && bytes.Length != 2 && bytes.Length != 4 && bytes.Length != 8) + 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); } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Bytes. public UID(ReadOnlySpan bytes) { - if (bytes.Length != 1 && bytes.Length != 2 && bytes.Length != 4 && bytes.Length != 8) + 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); } /// - /// Initializes a new instance of the class using an unsigned 8-bit number. + /// Initializes a new instance of the class using an unsigned 8-bit number. /// /// Name. /// Unsigned 8-bit number. [Obsolete("UIDs have no meaningful names")] - public UID(String name, byte number) + public UID(string name, byte number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using an unsigned 8-bit number. + /// Initializes a new instance of the class using an unsigned 8-bit number. /// /// Unsigned 8-bit number. public UID(byte number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using a signed 8-bit number. + /// Initializes a new instance of the class using a signed 8-bit number. /// /// Name. /// Unsigned 8-bit number. [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; } /// - /// Initializes a new instance of the class using an unsigned 16-bit number. + /// Initializes a new instance of the class using an unsigned 16-bit number. /// /// Name. /// Unsigned 16-bit number. [Obsolete("UIDs have no meaningful names")] - public UID(String name, ushort number) + public UID(string name, ushort number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using an unsigned 16-bit number. + /// Initializes a new instance of the class using an unsigned 16-bit number. /// /// Name. /// Unsigned 16-bit number. public UID(ushort number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using a signed 16-bit number. + /// Initializes a new instance of the class using a signed 16-bit number. /// /// Name. /// Signed 16-bit number. [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; } /// - /// Initializes a new instance of the class using an unsigned 32-bit number. + /// Initializes a new instance of the class using an unsigned 32-bit number. /// /// Name. /// Unsigned 32-bit number. [Obsolete("UIDs have no meaningful names")] - public UID(String name, uint number) + public UID(string name, uint number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using an unsigned 32-bit number. + /// Initializes a new instance of the class using an unsigned 32-bit number. /// /// Unsigned 32-bit number. public UID(uint number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using a signed 32-bit number. + /// Initializes a new instance of the class using a signed 32-bit number. /// /// Name. /// Signed 32-bit number. [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; } /// - /// Initializes a new instance of the class using an unsigned 64-bit number. + /// Initializes a new instance of the class using an unsigned 64-bit number. /// /// Name. /// Unsigned 64-bit number. [Obsolete("UIDs have no meaningful names")] - public UID(String name, ulong number) + public UID(string name, ulong number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using an unsigned 64-bit number. + /// Initializes a new instance of the class using an unsigned 64-bit number. /// /// Unsigned 64-bit number. public UID(ulong number) { - this.value = number; + value = number; } /// - /// Initializes a new instance of the class using a signed 64-bit number. + /// Initializes a new instance of the class using a signed 64-bit number. /// /// Name. /// Signed 64-bit number. [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; } /// - /// Gets the bytes. + /// Gets the bytes. /// /// The bytes. public byte[] Bytes { get { - byte[] bytes = new byte[this.ByteCount]; - this.GetBytes(bytes); + byte[] bytes = new byte[ByteCount]; + GetBytes(bytes); return bytes; } } /// - /// Gets the number of bytes required to represent this . + /// Gets the number of bytes required to represent this . /// public int ByteCount { 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 - { - return 8; - } + if(value <= byte.MaxValue) return 1; + + if(value <= ushort.MaxValue) return 2; + if(value <= uint.MaxValue) return 4; + + return 8; } } /// - /// Writes the bytes required to represent this to a byte span. - /// - /// - /// The byte span to which to write the byte representation of this UID. - /// - public void GetBytes(Span bytes) - { - switch (this.ByteCount) - { - case 1: - bytes[0] = (byte)this.value; - break; - - case 2: - BinaryPrimitives.WriteUInt16BigEndian(bytes, (ushort)this.value); - break; - - case 4: - BinaryPrimitives.WriteUInt32BigEndian(bytes, (uint)this.value); - break; - - case 8: - BinaryPrimitives.WriteUInt64BigEndian(bytes, this.value); - break; - - default: - throw new InvalidOperationException(); - } - } - - /// - /// Gets the name. + /// Gets the name. /// /// The name. [Obsolete("UIDs have no meaningful names")] - public string Name + public string Name => value.ToString(); + + /// + /// Writes the bytes required to represent this to a byte span. + /// + /// + /// The byte span to which to write the byte representation of this UID. + /// + public void GetBytes(Span bytes) { - get + switch(ByteCount) { - return this.value.ToString(); + case 1: + bytes[0] = (byte)value; + break; + + case 2: + BinaryPrimitives.WriteUInt16BigEndian(bytes, (ushort)value); + break; + + case 4: + BinaryPrimitives.WriteUInt32BigEndian(bytes, (uint)value); + break; + + case 8: + BinaryPrimitives.WriteUInt64BigEndian(bytes, value); + break; + + default: throw new InvalidOperationException(); } } /// - /// There is no XML representation specified for UIDs. - /// In this implementation UIDs are represented as strings in the XML output. + /// There is no XML representation specified for UIDs. + /// In this implementation UIDs are represented as strings in the XML output. /// /// The xml StringBuilder /// The indentation level @@ -280,18 +266,17 @@ namespace Claunia.PropertyList { Indent(xml, level); xml.Append(""); - Span bytes = stackalloc byte[this.ByteCount]; - this.GetBytes(bytes); - foreach (byte b in bytes) - xml.Append(String.Format("{0:x2}", b)); + Span bytes = stackalloc byte[ByteCount]; + GetBytes(bytes); + foreach(byte b in bytes) xml.Append(string.Format("{0:x2}", b)); xml.Append(""); } internal override void ToBinary(BinaryPropertyListWriter outPlist) { - outPlist.Write(0x80 + this.ByteCount - 1); - Span bytes = stackalloc byte[this.ByteCount]; - this.GetBytes(bytes); + outPlist.Write(0x80 + ByteCount - 1); + Span bytes = stackalloc byte[ByteCount]; + GetBytes(bytes); outPlist.Write(bytes); } @@ -299,10 +284,9 @@ namespace Claunia.PropertyList { Indent(ascii, level); ascii.Append("\""); - Span bytes = stackalloc byte[this.ByteCount]; - this.GetBytes(bytes); - foreach (byte b in bytes) - ascii.Append(String.Format("{0:x2}", b)); + Span bytes = stackalloc byte[ByteCount]; + GetBytes(bytes); + foreach(byte b in bytes) ascii.Append(string.Format("{0:x2}", b)); ascii.Append("\""); } @@ -312,38 +296,42 @@ namespace Claunia.PropertyList } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current + /// . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is equal to the current + /// ; otherwise, false. + /// public override bool Equals(NSObject obj) { return Equals((object)obj); } - /// + /// 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; } - /// + /// public override int GetHashCode() { - return this.value.GetHashCode(); + return value.GetHashCode(); } - /// + /// public override string ToString() { - return $"{this.value} (UID)"; + return $"{value} (UID)"; } } -} - +} \ No newline at end of file diff --git a/plist-cil/XmlPropertyListParser.cs b/plist-cil/XmlPropertyListParser.cs index 7e6a024..f5ce9f5 100644 --- a/plist-cil/XmlPropertyListParser.cs +++ b/plist-cil/XmlPropertyListParser.cs @@ -22,22 +22,23 @@ // 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 { /// - /// Parses XML property lists. + /// Parses XML property lists. /// /// @author Daniel Dreibrodt /// @author Natalia Portillo public static class XmlPropertyListParser { /// - /// Parses a XML property list file. + /// Parses a XML property list file. /// /// The XML property list file. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -45,19 +46,17 @@ 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); - } + using(Stream stream = f.OpenRead()) + using(XmlReader reader = XmlReader.Create(stream, settings)) + doc.Load(reader); return ParseDocument(doc); } /// - /// Parses a XML property list from a byte array. + /// Parses a XML property list from a byte array. /// /// The byte array containing the property list's data. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -68,7 +67,7 @@ namespace Claunia.PropertyList } /// - /// Parses a XML property list from an input stream. + /// Parses a XML property list from an input stream. /// /// The input stream pointing to the property list's data. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -79,16 +78,13 @@ 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); } /// - /// Parses a XML property list from a string. + /// Parses a XML property list from a string. /// /// The string pointing to the property list's data. /// The root object of the property list. This is usually a NSDictionary but can also be a NSArray. @@ -105,40 +101,35 @@ namespace Claunia.PropertyList } /// - /// Parses the XML document by generating the appropriate NSObjects for each XML node. + /// Parses the XML document by generating the appropriate NSObjects for each XML node. /// /// The root NSObject of the property list contained in the XML document. /// The XML document. static NSObject ParseDocument(XmlDocument doc) { - var docType = doc.ChildNodes - .OfType() - .SingleOrDefault(n => n.NodeType == XmlNodeType.DocumentType); + XmlNode docType = doc.ChildNodes.OfType() + .SingleOrDefault(n => n.NodeType == XmlNodeType.DocumentType); - if (docType == null) + if(docType == null) { - if (!doc.DocumentElement.Name.Equals("plist")) - { + if(!doc.DocumentElement.Name.Equals("plist")) throw new XmlException("The given XML document is not a property list."); - } } - else if (!docType.Name.Equals("plist")) - { + else if(!docType.Name.Equals("plist")) throw new XmlException("The given XML document is not a property list."); - } XmlNode rootNode; - if (doc.DocumentElement.Name.Equals("plist")) + if(doc.DocumentElement.Name.Equals("plist")) { //Root element wrapped in plist tag List rootNodes = FilterElementNodes(doc.DocumentElement.ChildNodes); - if (rootNodes.Count == 0) + 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 @@ -148,17 +139,17 @@ namespace Claunia.PropertyList } /// - /// Parses a node in the XML structure and returns the corresponding NSObject + /// Parses a node in the XML structure and returns the corresponding NSObject /// /// The corresponding NSObject. /// The XML node. static NSObject ParseObject(XmlNode n) { - if (n.Name.Equals("dict")) + if(n.Name.Equals("dict")) { - NSDictionary dict = new NSDictionary(); + NSDictionary dict = new NSDictionary(); List children = FilterElementNodes(n.ChildNodes); - for (int i = 0; i < children.Count; i += 2) + for(int i = 0; i < children.Count; i += 2) { XmlNode key = children[i]; XmlNode val = children[i + 1]; @@ -167,78 +158,73 @@ namespace Claunia.PropertyList dict.Add(keyString, ParseObject(val)); } + return dict; } - if (n.Name.Equals("array")) + + if(n.Name.Equals("array")) { List children = FilterElementNodes(n.ChildNodes); - NSArray array = new NSArray(children.Count); - for (int i = 0; i < children.Count; i++) - { - array.Add(ParseObject(children[i])); - } + NSArray array = new NSArray(children.Count); + 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; } /// - /// Returns all element nodes that are contained in a list of nodes. + /// Returns all element nodes that are contained in a list of nodes. /// /// The sublist containing only nodes representing actual elements. /// The list of nodes to search. static List FilterElementNodes(XmlNodeList list) { List result = new List(); - foreach (XmlNode child in list) - if (child.NodeType == XmlNodeType.Element) + foreach(XmlNode child in list) + if(child.NodeType == XmlNodeType.Element) result.Add(child); return result; } /// - /// Returns a node's text content. - /// This method will return the text value represented by the node's direct children. - /// If the given node is a TEXT or CDATA node, then its value is returned. + /// Returns a node's text content. + /// This method will return the text value represented by the node's direct children. + /// If the given node is a TEXT or CDATA node, then its value is returned. /// /// The node's text content. /// The node. static string GetNodeTextContents(XmlNode n) { - if (n.NodeType == XmlNodeType.Text || n.NodeType == XmlNodeType.CDATA) + if(n.NodeType == XmlNodeType.Text || n.NodeType == XmlNodeType.CDATA) { string content = n.Value; //This concatenates any adjacent text/cdata/entity nodes return content ?? ""; } - if (n.HasChildNodes) + + if(n.HasChildNodes) { XmlNodeList children = n.ChildNodes; - foreach (XmlNode child in children) - { + foreach(XmlNode child in children) //Skip any non-text nodes, like comments or entities - if (child.NodeType == XmlNodeType.Text || child.NodeType == XmlNodeType.CDATA) + 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 ""; } } -} - +} \ No newline at end of file