81 Commits
v1.13 ... v1.16

Author SHA1 Message Date
b9977e92d3 Updated nuspec. 2017-05-20 05:11:14 +01:00
302bfca681 Bumped version to 1.16. 2017-05-20 05:08:30 +01:00
01b62a907c Add explicit casting overrides. Fixes #26. 2017-05-20 05:02:55 +01:00
df68433456 Updated readme. Fixes #1. 2017-05-20 04:49:07 +01:00
96b66d2516 Updated travis file. 2017-05-20 04:04:13 +01:00
5a74d9f9ee Updated travis file. 2017-05-20 04:01:02 +01:00
2b0488f94a Remove non-existant file reference from solution. 2017-05-20 03:58:29 +01:00
fce5f88895 Changes how property lists are parsed and adds detection of empty files in more places. 2017-05-20 03:15:22 +01:00
9a10128482 Allow to parse hex numbers. 2017-05-20 02:54:32 +01:00
67b73b4319 Ignore line endings on test. 2017-05-20 02:53:39 +01:00
114fd9b2fc .NET has some kind of bug with DST. On winter time, TestXml() works. On summer time, TestXml() fails by the amount modified by time savings. Workaround it. 2017-05-20 02:34:00 +01:00
673825548f Consider all ASCIIPropertyLists as UTF8 on opening, instead of considering them ASCII. Fixes #15. 2017-05-20 02:27:53 +01:00
25e2063112 Merge pull request #21 from quamotion/fixes/binary-compatibility
Binary compatibility with the Apple Plist format
2017-05-20 01:44:56 +01:00
1979dab8fa Support creating UIDs from numbers. Closes #3. 2017-05-20 01:31:50 +01:00
c8d3e26a84 Updated README. 2017-05-20 00:58:28 +01:00
a2ace4f4d8 Added netstandard1.4, with this it should cover all frameworks. 2017-05-20 00:46:16 +01:00
4af6672d37 Merge pull request #25 from quamotion/features/unittests
Migrate to xUnit
2017-03-22 14:26:59 +00:00
Frederik Carlier
65f12a2607 Fix issue with DTD loading on .NET Core 2017-03-16 23:46:02 +01:00
Frederik Carlier
d9670db803 Migrate to xUnit 2017-03-16 23:37:42 +01:00
50335a9bba Merge pull request #20 from quamotion/fixes/content-property
Use a property for Content instead of GetContent/SetContent
2017-03-16 22:05:04 +00:00
f56f0606f1 Merge pull request #22 from quamotion/fixes/appveyor
Update AppVeyor build script
2017-03-16 22:03:47 +00:00
65a932dfd7 Merge branch 'master' into fixes/appveyor 2017-03-16 22:02:51 +00:00
b2a1f093b0 Merge pull request #23 from quamotion/features/netcore
Support NETStandard 1.3, 1.6
2017-03-16 21:54:15 +00:00
Frederik Carlier
7982cad715 Support NETStandard 1.3, 1.6 2017-03-07 16:27:19 +01:00
Frederik Carlier
4f31fc611f Fix Push-Artificat 2017-03-07 15:01:57 +01:00
Frederik Carlier
e0d0baa985 Update version number 2017-03-07 14:59:12 +01:00
Frederik Carlier
bed10a35ca Allow version number suffixes 2017-03-07 14:55:24 +01:00
Frederik Carlier
1399b4ba2a Fix AppVeyor script 2017-03-07 14:52:02 +01:00
Frederik Carlier
e20798c746 Fix path to .nuspec file 2017-03-07 14:46:19 +01:00
Frederik Carlier
fb29bb8131 Update .gitignore file 2017-03-07 14:46:02 +01:00
Frederik Carlier
b07e637c6d Add AppVeyour build script 2017-03-07 14:45:48 +01:00
Frederik Carlier
b4974acba9 Don't reuse object IDs for NSNumber objects
Make the constructors and Write methods public
2017-03-07 14:43:56 +01:00
Frederik Carlier
8dc5f8ba24 Make sure that the NSString which represents keys in a NSDictionary is always the same value, by caching the string to NSString conversion in a dictionary 2017-03-07 14:43:22 +01:00
Frederik Carlier
6c95260157 Maintain binary compatibility with the Apple format: disable optimizations and add the same UID, NSArray and NSString values multiple times to the property list file. 2017-03-07 14:40:09 +01:00
Frederik Carlier
275f7fdd8f Use a property for Content instead of GetContent/SetContent 2017-03-07 14:38:19 +01:00
e071148e2b Updated code to correclty support and compile using .NET Core RC4 (and Visual Studio 2017). May break compatibility with VS2015. Older .NET Core will not be supported. Fixes #13
Signed-off-by: Natalia Portillo <claunia@claunia.com>
2017-02-22 21:25:31 +00:00
c646d1beb2 Merge pull request #12 from quamotion/fixes/dtd-processing
Ignore DTD when reading XML PList documents
2016-07-09 14:25:56 +01:00
Frederik Carlier
fb7e431ac8 Ignore DTD when reading XML PList documents 2016-06-28 20:42:59 +02:00
64dc55d047 Merge pull request #8 from quamotion/fixes/xml-formatting
XML format compatibility with Apple
2016-06-24 22:04:12 +01:00
036227e346 Merge pull request #9 from quamotion/fixes/date-handling
Fix date handling
2016-06-24 22:03:49 +01:00
Frederik Carlier
03c95ce192 Minor fixes in how property lists are serialized to XML, to maintain compatibility with the Apple format:
- NSNumber of "0/real" is serialized as "0.0"
- Data values are not indented
- Newline at the end of the file
- Always use \r as newline
2016-06-22 13:13:55 +02:00
Frederik Carlier
c2f15567c7 Fix the datetime test (use the correct UTC value) 2016-06-22 13:11:52 +02:00
Frederik Carlier
dfee77b724 When converting dates to strings, always convert them to UTC first. 2016-06-22 13:11:52 +02:00
Frederik Carlier
1ff1bcde3b Parse dates as UTC dates. 2016-06-22 13:11:52 +02:00
2148034a71 Merge pull request #11 from quamotion/fixes/create-new-file
Always create a new file when writing to disk.
2016-06-22 05:10:45 +01:00
10e92e31db Merge pull request #10 from quamotion/fixes/0-length-stream
Fix issues with 0-length streams
2016-06-22 05:10:40 +01:00
18e9e294e2 Merge pull request #7 from quamotion/fixes/nsarray-recursion
Fix recursive call in NSArray.GetEnumerator
2016-06-22 05:10:27 +01:00
b9aa325825 Merge pull request #6 from quamotion/fixes/nsnumber-from-xml
NSNumber: Keep track of the original number type when parsing from XML
2016-06-22 05:10:22 +01:00
Frederik Carlier
bf031fadab Always create a new file when writing to disk. 2016-06-03 16:04:22 +02:00
Frederik Carlier
66ac10e4be Make sure to always specify CultureInfo when parsing numbers. 2016-06-03 15:39:54 +02:00
Frederik Carlier
12418b7284 Fix issue when handling 0-length streams. 2016-05-25 00:37:44 +02:00
Frederik Carlier
3c4e3257f2 NSNumber: Keep track of the original number type when parsing from XML 2016-05-24 23:43:00 +02:00
Frederik Carlier
e432c71e26 Fix recursive call in NSArray.GetEnumerator 2016-05-24 22:55:24 +02:00
6571783fab Merge pull request #4 from quamotion/fixes/dotnetcore
.NET Core Compatibility
2016-05-23 00:35:49 +01:00
Frederik Carlier
a58ff42cef Add .NET Core compatibility to the README file 2016-05-23 00:19:07 +02:00
Frederik Carlier
5d16fb0275 Don't use the $ syntax 2016-05-22 19:35:17 +02:00
Frederik Carlier
55c515bd39 Add more recent Mono releases (from the 3.x and 4.x branch) 2016-05-22 19:35:10 +02:00
Frederik Carlier
ec6d00342f Update unit tests after updates to work on .NET Core 2016-05-22 19:12:44 +02:00
Frederik Carlier
22737bb9d2 Convert.ToBase64String: Formatting parameters are no longer supported 2016-05-22 19:12:43 +02:00
Frederik Carlier
8f04882f98 Work around DocumentType which is no longer available on .NET Core 2016-05-22 19:12:43 +02:00
Frederik Carlier
bdf4351d1d Remove Synchronized attribute - method uses no global resources 2016-05-22 19:12:42 +02:00
Frederik Carlier
844d9f3b12 Remove the BinarySerialization. It's not available anymore on .NET Core, and if you want to serialize a .NET object to byte[] - let the caller specify how it should be done (and pass the byte[] array itself) 2016-05-22 19:12:41 +02:00
Frederik Carlier
cbfb5c8290 .NET Core Compatibility: string.CharEnumeator -> string.ToCharArray().GetEnumerator 2016-05-22 19:12:40 +02:00
Frederik Carlier
f284d2abd0 Don't use SystemException but a PropertyListException to indicate something went wrong. 2016-05-22 19:12:34 +02:00
Frederik Carlier
0a7483ff75 Use using statements around Streams and Readers/Writers instead of manually calling .Close, which is no longer supported on .NET Core 2016-05-22 19:12:26 +02:00
accdc880ae Merge pull request #5 from quamotion/fixes/dotnetinterfaces
NSArray: Implement IList<NSObject>
2016-05-22 15:51:54 +01:00
Frederik Carlier
2bacfb7037 Update the parsing code to match to work with the new NSArray class 2016-05-22 16:37:44 +02:00
Frederik Carlier
df27f9d5ac NSArray: Implement IList<NSObject> 2016-05-22 16:05:33 +02:00
ccfba8ebc1 Merge pull request #2 from quamotion/fixes/binary-plist
Minor enhancements to plist-cil
2016-02-16 14:44:21 +00:00
Frederik Carlier
5a1a9d18d7 Binary format: Even if equivalent arrays (like empty ones) are saved, save them multiple times and use their respective indices 2016-02-10 13:41:54 +01:00
Frederik Carlier
156a55c84a BinaryPropertyListWriter: Allow for multiple occurences of the same UID, to maintain compatibility with the Apple binary format 2016-02-10 01:58:29 +01:00
Frederik Carlier
6f03f99db4 Support serializing empty (0-length) arrays 2016-02-05 19:48:54 +01:00
Frederik Carlier
1d3f49824c Fix order in which object IDs are generated to match the behavior of Apple's PLIST implementation 2016-02-05 19:48:33 +01:00
Frederik Carlier
438c75173b Enable strong name signing of the project 2016-02-05 17:02:36 +01:00
7ceae0ddc3 Corrected copy&paste :p 2015-10-24 01:19:42 +01:00
cf2b51e41d Added Travis job 2015-10-24 01:16:13 +01:00
a469709814 Added gnustep tag to NuSpec 2015-02-25 18:29:34 +00:00
d17e1f56a0 Added summary and better description. 2015-02-25 18:22:29 +00:00
fbd57a18be Update README.md to reflect current NuGet status. 2015-02-25 18:17:30 +00:00
df673df0a9 * plist-cil/plist-cil.nuspec:
* plist-cil/plist-cil.csproj:
	  Added NuGet package.

	* SvnInfo.txt:
	  Sync'ed with svn r114
2015-02-25 18:06:20 +00:00
399a043c62 * plist-cil.sln:
* plist-cil/plist-cil.csproj:
	* plist-cil.test/plist-cil.test.csproj:
	* plist-cil/Properties/AssemblyInfo.cs:
	  Bump to 1.14 (upstream r114).

	* plist-cil/PropertyListParser.cs:
	* plist-cil/ASCIIPropertyListParser.cs:
	  Sync BOM skipping code with upstream.

	* plist-cil/BinaryPropertyListParser.cs:
	  Sync code with upstream.
	Added UTF-8 string decoding on binary property lists.
2015-02-24 22:53:31 +00:00
41 changed files with 1867 additions and 643 deletions

5
.gitignore vendored
View File

@@ -1,3 +1,6 @@
*.vs/
*.orig
*.nupkg
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
@@ -174,3 +177,5 @@ UpgradeLog*.htm
FakesAssemblies/
*.userprefs
.vs/

15
.travis.yml Normal file
View File

@@ -0,0 +1,15 @@
language: csharp
solution: plist-cil.sln
mono:
- latest
- alpha
- beta
- weekly
- 4.2.3
- 4.0.5
- 3.10.0
- 3.8.0
- 3.2.8
- 2.10.8
dotnet: 1.0.1
dist: trusty

View File

@@ -1,3 +1,27 @@
2017-02-22 Natalia Portillo <claunia@claunia.com>
* SvnInfo.txt:
Removed, no longer tracking from SVN.
* plist-cil.csproj:
Updated for .NET Core.
* .travis.yml:
Added .NET Core target.
* .gitignore:
Ignore .vs settings folder.
2015-02-25 Natalia Portillo <claunia@claunia.com>
* SvnInfo.txt:
Sync'ed with svn r114
2015-02-24 Natalia Portillo <claunia@claunia.com>
* plist-cil.sln:
Bump to 1.14 (upstream r114).
2015-02-20 Natalia Portillo <claunia@claunia.com>
* SvnInfo.txt:

155
README.md
View File

@@ -1,33 +1,148 @@
#plist-cil
This library enables .NET (CLR) applications to work with property lists in various formats.
It is mostly based on [dd-plist for Java](https://code.google.com/p/plist/).
# plist-cil - A C# library for working with property lists
You can parse existing property lists (e.g. those created by an iOS application) and work with the contents on any operating system.
[![Build Status](https://travis-ci.org/claunia/plist-cil.svg?branch=faster)](httsp://travis-ci.org/claunia/plist-cil)
The library also enables you to create your own property lists from scratch and store them in various formats.
This library enables .NET (CLR) applications to handle property lists of various formats.
It is mostly based on [dd-plist for Java](https://github.com/3breadt/dd-plist).
And as it, this is licensed under the terms of the MIT license.
The provided API mimics the Cocoa/NeXTSTEP API, and where applicable, the .NET API, granting access to the basic functions of classes like NSDictionary, NSData, etc.
Property lists are files used to store user settings and serialized objects.
They originate from the NeXTSTEP programming environment and are now a basic part of thhe Cocoa framework (macOS and iOS) as well as the GNUstep framework.
###Supported formats
## Features
| Format | Read | Write |
| ---------------------- | ---- | ----- |
| OS X / iOS XML | yes | yes |
| OS X / iOS Binary (v0) | yes | yes |
| OS X / iOS ASCII | yes | yes |
| GNUstep ASCII | yes | yes |
* Read / write property lists from / to files, streams or byte arrays
* Convert between property lists formats
* Property list contents are provided as objects from the NeXTSTEP environment (NSDictionary, NSArray, NSString, etc.)
* Serialie native .NET data structures to property list objects
* Deserialize from property list objects to native .NET data structures
###Requirements
.NET Framework 4.0 or Mono.
## Supported formats
###Download
* Cocoa XML
* Cocoa Binary (v0)
* Cocoa / NeXTSTEP / GNUstep ASCII
The latest releases can be downloaded [here](https://github.com/claunia/plist-cil/releases):
## Requirements
.NET Framework 4.0, Mono or .NET Core.
Targets .NET Framework 4.0, .NET Framework 4.5, .NET Standard 1.3, .NET Standard 1.4 and .NET Standard 1.6 so it should be compatible with Mono, Xamarin.iOS, Xamarin.Mac, UWP, etc.
If you find an incompatibility, please create an issue.
###NuGet support
Coming soon......
## Download
###Help
The latest releases can be downloaded [here](https://github.com/claunia/plist-cil/releases).
## NuGet support
You can download the NuGet package directly from the [release](https://github.com/claunia/plist-cil/releases) page or from the [NuGet Gallery](https://www.nuget.org/) or from [here](https://www.nuget.org/packages/plist-cil/).
## Help
The API documentation is included in the download.
When you encounter a bug please report it by on the [issue tracker](https://github.com/claunia/plist-cil/issues).
## Usage examples
### Reading
Parsing can be done with the PropertyListParser class. You can feed the `PropertyListParser` with a `FileInfo`, a `Stream` or a `byte` array.
The `Parse` method of the `PropertyListParser` will parse the input and give you a `NSObject` as result. Generally this is a `NSDictionary` but it can also be a `NSArray`.
_Note: Property lists created by `NSKeyedArchiver` are not yet supported._
You can then navigate the contents of the property lists using the various classes extending `NSObject`. These are modeled in such a way as to closely resemble the respective Cocoa classes.
You can also directly convert the contained `NSObject` objects into native .NET Objects with the `NSOBject.ToObject()` method. Using this method you can avoid working with `NSObject` instances altogether.
### Writing
You can create your own property list using the various constructors of the different `NSObject` classes. Or you can wrap existing native .NET structures with the method `NSObject.Wrap(Object o)`. Just make sure that the root object of the property list is either a `NSDictionary` (can be created from objects of the type `Dictionary<string, Object>`) or a `NSArray` (can be created from object arrays).
For building a XML property list you can then call the `ToXml` method on the root object of your property list. It will give you an UTF-8 `string` containing the property list in XML format.
If you want to have the property list in binary format use the `BinaryPropertyListWriter` class. It can write the binary property list directly to a file or to a `Stream`.
When you directly want to save your property list to a file, you can also use the `SaveAsXml` or `SaveAsBinary` methods of the `PropertyListParser` class.
### Converting
For converting a file into another format there exist convenience methods in the `PropertyListParser` class: `ConvertToXml`, `ConvertToBinary`, `ConvertToASCII` and `ConvertToGnuStepASCII`.
## Code snippets
### Reading
try
{
FileInfo file = new FileInfo("Info.plist");
NSDictionary rootDict = (NSDictionary)PropertyListParser.Parse(file);
string name = rootDict.ObjectForKey("Name").ToString();
NSObject[] parameters = ((NSArray)rootDict.ObjectForKey("Parameters")).GetArray();
foreach(NSObject param in parameters)
{
if(param.GetType().Equals(typeof(NSNumber)))
{
NSNumber num = (NSNumber)param;
switch(num.GetNSNumberType())
{
case NSNumber.BOOLEAN:
{
boolean bool = num.ToBool();
// ...
break;
}
case NSNumber.INTEGER:
{
long l = num.ToLong();
// or int i = num.ToInt();
// ...
break;
}
case NSNumber.REAL:
{
double d = num.ToDouble();
// ...
break;
}
}
}
// else...
}
}
catch(Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
### Writing
// Creating the root object
NSDictionary root = new NSDictionary();
// Creation of an array of length 2
NSArray people = new NSArray(2);
// Creation of the first object to be stored in the array
NSDictionary person1 = new NSDictionary();
// The NSDictionary will automatically wrap strings, numbers and dates in the respective NSObject subclasses
person1.Add("Name", "Peter"); // This will become a NSString
// Use the DateTime class
person1.Add("RegistrationDate", new DateTime(2011, 1, 13, 9, 28, 0)); // This will become a NSDate
person1.Add("Age", 23); // This will become a NSNumber
person1.Add("Photo", new NSData(new FileInfo("peter.jpg")));
// Creation of the second object to be stored in the array
NSDictionary person2 = new NSDictionary();
person2.Add("Name", "Lisa");
person2.Add("Age", 42);
person2.Add("RegistrationDate", new NSDate("2010-09-23T12:32:42Z"));
person2.Add("Photo", new NSData(new FileInfo("lisa.jpg")));
// Put the objects into the array
people.SetValue(0, person1);
people.SetValue(1, person2);
// Put the array into the property list
root.Add("People", people);
// Save the property list
PropertyListParser.SaveAsXml(root, new FileInfo("people.plist"));

View File

@@ -1,12 +0,0 @@
Path: .
Working Copy Root Path: /Development/plist
URL: http://plist.googlecode.com/svn/trunk
Repository Root: http://plist.googlecode.com/svn
Repository UUID: 08b5d097-3e27-63a3-4c6f-efc316e1e7e5
Revision: 113
Node Kind: directory
Schedule: normal
Last Changed Author: daniel.dreibrodt@gmail.com
Last Changed Rev: 113
Last Changed Date: 2014-11-17 16:31:28 +0000 (lun, 17 nov 2014)

15
appveyor.yml Normal file
View File

@@ -0,0 +1,15 @@
install:
- choco install -y wget
- wget -q https://download.microsoft.com/download/5/F/E/5FEB7E95-C643-48D5-8329-9D2C63676CE8/dotnet-dev-win-x64.1.0.0-rc4-004771.exe
- dotnet-dev-win-x64.1.0.0-rc4-004771.exe /install /quiet /log dotnetinstall.log
- ps: Push-AppveyorArtifact "dotnetinstall.log"
build_script:
- cmd: cd plist-cil
- cmd: dotnet restore
- cmd: dotnet build -c Release --version-suffix r%APPVEYOR_BUILD_NUMBER%
- cmd: dotnet test plist-cil.test\plist-cil.test.csproj
on_success:
- cmd: dotnet pack -c Release --version-suffix r%APPVEYOR_BUILD_NUMBER%
- ps: Push-AppveyorArtifact "bin\Release\plist-cil.1.15.0-r$($env:APPVEYOR_BUILD_NUMBER).nupkg"

View File

@@ -1,38 +1,68 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "plist-cil", "plist-cil\plist-cil.csproj", "{5EA40CD5-CB98-4FD5-8628-3B399EACB38B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "plist-cil.test", "plist-cil.test\plist-cil.test.csproj", "{36AD4394-6A31-465F-BE8E-E4806A89CC38}"
EndProject
# Visual Studio 15
VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{25B9F55C-9830-4526-9539-949838B09EAC}"
ProjectSection(SolutionItems) = preProject
SvnInfo.txt = SvnInfo.txt
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "plist-cil", "plist-cil\plist-cil.csproj", "{2A906AEB-BDE0-4356-8114-064F80596C7D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "plist-cil.test", "plist-cil.test\plist-cil.test.csproj", "{17124CCE-32F1-4FD6-8703-32235BDEEEDC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{36AD4394-6A31-465F-BE8E-E4806A89CC38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36AD4394-6A31-465F-BE8E-E4806A89CC38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36AD4394-6A31-465F-BE8E-E4806A89CC38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36AD4394-6A31-465F-BE8E-E4806A89CC38}.Release|Any CPU.Build.0 = Release|Any CPU
{5EA40CD5-CB98-4FD5-8628-3B399EACB38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5EA40CD5-CB98-4FD5-8628-3B399EACB38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5EA40CD5-CB98-4FD5-8628-3B399EACB38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5EA40CD5-CB98-4FD5-8628-3B399EACB38B}.Release|Any CPU.Build.0 = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|ARM.Build.0 = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|x64.ActiveCfg = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|x64.Build.0 = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|x86.ActiveCfg = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Debug|x86.Build.0 = Debug|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|Any CPU.Build.0 = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|ARM.ActiveCfg = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|ARM.Build.0 = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|x64.ActiveCfg = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|x64.Build.0 = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|x86.ActiveCfg = Release|Any CPU
{2A906AEB-BDE0-4356-8114-064F80596C7D}.Release|x86.Build.0 = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|ARM.ActiveCfg = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|ARM.Build.0 = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|x64.ActiveCfg = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|x64.Build.0 = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|x86.ActiveCfg = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Debug|x86.Build.0 = Debug|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|Any CPU.Build.0 = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|ARM.ActiveCfg = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|ARM.Build.0 = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|x64.ActiveCfg = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|x64.Build.0 = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|x86.ActiveCfg = Release|Any CPU
{17124CCE-32F1-4FD6-8703-32235BDEEEDC}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.DotNetNamingPolicy = $1
$1.DirectoryNamespaceAssociation = PrefixedHierarchical
$1.ResourceNamePolicy = MSBuild
$0.TextStylePolicy = $2
$0.TextStylePolicy = $4
$2.inheritsSet = VisualStudio
$2.inheritsScope = text/plain
$2.scope = text/x-csharp
@@ -61,7 +91,6 @@ Global
$3.inheritsSet = Mono
$3.inheritsScope = text/x-csharp
$3.scope = text/x-csharp
$0.TextStylePolicy = $4
$4.inheritsSet = VisualStudio
$4.inheritsScope = text/plain
$4.scope = text/plain
@@ -70,21 +99,19 @@ Global
$5.IncludeInNewFiles = True
$0.NameConventionPolicy = $6
$6.Rules = $7
$7.NamingRule = $8
$7.NamingRule = $32
$8.Name = Namespaces
$8.AffectedEntity = Namespace
$8.VisibilityMask = VisibilityMask
$8.NamingStyle = PascalCase
$8.IncludeInstanceMembers = True
$8.IncludeStaticEntities = True
$7.NamingRule = $9
$9.Name = Types
$9.AffectedEntity = Class, Struct, Enum, Delegate
$9.VisibilityMask = VisibilityMask
$9.NamingStyle = PascalCase
$9.IncludeInstanceMembers = True
$9.IncludeStaticEntities = True
$7.NamingRule = $10
$10.Name = Interfaces
$10.RequiredPrefixes = $11
$11.String = I
@@ -93,7 +120,6 @@ Global
$10.NamingStyle = PascalCase
$10.IncludeInstanceMembers = True
$10.IncludeStaticEntities = True
$7.NamingRule = $12
$12.Name = Attributes
$12.RequiredSuffixes = $13
$13.String = Attribute
@@ -102,7 +128,6 @@ Global
$12.NamingStyle = PascalCase
$12.IncludeInstanceMembers = True
$12.IncludeStaticEntities = True
$7.NamingRule = $14
$14.Name = Event Arguments
$14.RequiredSuffixes = $15
$15.String = EventArgs
@@ -111,7 +136,6 @@ Global
$14.NamingStyle = PascalCase
$14.IncludeInstanceMembers = True
$14.IncludeStaticEntities = True
$7.NamingRule = $16
$16.Name = Exceptions
$16.RequiredSuffixes = $17
$17.String = Exception
@@ -120,97 +144,82 @@ Global
$16.NamingStyle = PascalCase
$16.IncludeInstanceMembers = True
$16.IncludeStaticEntities = True
$7.NamingRule = $18
$18.Name = Methods
$18.AffectedEntity = Methods
$18.VisibilityMask = VisibilityMask
$18.NamingStyle = PascalCase
$18.IncludeInstanceMembers = True
$18.IncludeStaticEntities = True
$7.NamingRule = $19
$19.Name = Static Readonly Fields
$19.AffectedEntity = ReadonlyField
$19.VisibilityMask = Internal, Protected, Public
$19.NamingStyle = PascalCase
$19.IncludeInstanceMembers = False
$19.IncludeStaticEntities = True
$7.NamingRule = $20
$20.Name = Fields (Non Private)
$20.AffectedEntity = Field
$20.VisibilityMask = Internal, Protected, Public
$20.NamingStyle = PascalCase
$20.IncludeInstanceMembers = True
$20.IncludeStaticEntities = True
$7.NamingRule = $21
$21.Name = ReadOnly Fields (Non Private)
$21.AffectedEntity = ReadonlyField
$21.VisibilityMask = Internal, Protected, Public
$21.NamingStyle = PascalCase
$21.IncludeInstanceMembers = True
$21.IncludeStaticEntities = False
$7.NamingRule = $22
$22.Name = Fields (Private)
$22.AllowedPrefixes = $23
$23.String = _
$23.String = m_
$22.AffectedEntity = Field, ReadonlyField
$22.VisibilityMask = Private
$22.NamingStyle = CamelCase
$22.IncludeInstanceMembers = True
$22.IncludeStaticEntities = False
$7.NamingRule = $24
$24.Name = Static Fields (Private)
$24.AffectedEntity = Field
$24.VisibilityMask = Private
$24.NamingStyle = CamelCase
$24.IncludeInstanceMembers = False
$24.IncludeStaticEntities = True
$7.NamingRule = $25
$25.Name = ReadOnly Fields (Private)
$25.AllowedPrefixes = $26
$26.String = _
$26.String = m_
$25.AffectedEntity = ReadonlyField
$25.VisibilityMask = Private
$25.NamingStyle = CamelCase
$25.IncludeInstanceMembers = True
$25.IncludeStaticEntities = False
$7.NamingRule = $27
$27.Name = Constant Fields
$27.AffectedEntity = ConstantField
$27.VisibilityMask = VisibilityMask
$27.NamingStyle = PascalCase
$27.IncludeInstanceMembers = True
$27.IncludeStaticEntities = True
$7.NamingRule = $28
$28.Name = Properties
$28.AffectedEntity = Property
$28.VisibilityMask = VisibilityMask
$28.NamingStyle = PascalCase
$28.IncludeInstanceMembers = True
$28.IncludeStaticEntities = True
$7.NamingRule = $29
$29.Name = Events
$29.AffectedEntity = Event
$29.VisibilityMask = VisibilityMask
$29.NamingStyle = PascalCase
$29.IncludeInstanceMembers = True
$29.IncludeStaticEntities = True
$7.NamingRule = $30
$30.Name = Enum Members
$30.AffectedEntity = EnumMember
$30.VisibilityMask = VisibilityMask
$30.NamingStyle = PascalCase
$30.IncludeInstanceMembers = True
$30.IncludeStaticEntities = True
$7.NamingRule = $31
$31.Name = Parameters
$31.AffectedEntity = Parameter
$31.VisibilityMask = VisibilityMask
$31.NamingStyle = CamelCase
$31.IncludeInstanceMembers = True
$31.IncludeStaticEntities = True
$7.NamingRule = $32
$32.Name = Type Parameters
$32.RequiredPrefixes = $33
$33.String = T
@@ -233,6 +242,6 @@ Global
$37.IncludeDirectoryPaths = True
$36.inheritsSet = Mono
description = @This library enables .NET applications to work with property lists in various formats.\n\tSupported formats for reading and writing are OS X/iOS binary and XML property lists.\n ASCII property lists are also supported.\n\tThe library also provides access to basic functions of NeXTSTEP/Cocoa classes like\n NSDictionary, NSArray, etc.
version = 1.13
version = 1.14
EndGlobalSection
EndGlobal

View File

@@ -1,3 +1,22 @@
2017-02-22 Natalia Portillo <claunia@claunia.com>
* Properties/AssemblyInfo.cs:
Removed, no longer needed in .NET Core.
* plist-cil.test.csproj:
Updated for .NET Core
* NSNumberTests.cs:
Cannot test different locales with NUnit in .NET Core currently.
* PropertyListParserTests.cs:
Use different way to test for exceptions compatible with NUnit 3.6 and .NET Core.
2015-02-24 Natalia Portillo <claunia@claunia.com>
* plist-cil.test.csproj:
Bump to 1.14 (upstream r114).
2015-02-20 Natalia Portillo <claunia@claunia.com>
* IssueTest.cs:

View File

@@ -24,22 +24,21 @@
// SOFTWARE.
using System;
using System.IO;
using NUnit.Framework;
using Xunit;
using Claunia.PropertyList;
namespace plistcil.test
{
[TestFixture]
public static class IssueTest
{
[Test]
[Fact]
public static void TestIssue4()
{
NSDictionary d = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue4.plist"));
Assert.True(((NSString)d.ObjectForKey("Device Name")).ToString().Equals("Kid\u2019s iPhone"));
}
[Test]
[Fact]
public static void TestIssue7()
{
// also a test for issue 12
@@ -50,14 +49,14 @@ namespace plistcil.test
Assert.True(x.Equals(y));
}
[Test]
[Fact]
public static void TestIssue16()
{
float x = ((NSNumber)PropertyListParser.Parse(new FileInfo("test-files/issue16.plist"))).floatValue();
Assert.True(x == (float)2.71828);
}
[Test]
[Fact]
public static void TestIssue18()
{
NSNumber x = new NSNumber(-999);
@@ -66,14 +65,14 @@ namespace plistcil.test
Assert.True(x.Equals(y));
}
[Test]
[Fact]
public static void TestIssue21()
{
String x = ((NSString)PropertyListParser.Parse(new FileInfo("test-files/issue21.plist"))).ToString();
Assert.True(x.Equals("Lot&s of &persand&s and other escapable \"\'<>€ characters"));
}
[Test]
[Fact]
public static void TestIssue22()
{
NSDictionary x1 = ((NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue22-emoji.plist")));
@@ -96,7 +95,7 @@ namespace plistcil.test
Assert.True(emojiString.Equals(y2.ObjectForKey("emojiString").ToString()));
}
[Test]
[Fact]
public static void TestIssue30()
{
#pragma warning disable 219
@@ -104,7 +103,7 @@ namespace plistcil.test
#pragma warning restore 219
}
[Test]
[Fact]
public static void TestIssue33()
{
#pragma warning disable 219
@@ -112,7 +111,7 @@ namespace plistcil.test
#pragma warning restore 219
}
[Test]
[Fact]
public static void TestIssue38()
{
NSDictionary dict = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue33.pbxproj"));
@@ -120,11 +119,33 @@ namespace plistcil.test
Assert.True(fileRef.Equals(new NSString("65541A9B16D13B8C00A968D5")));
}
[Test]
[Fact]
public static void TestIssue49()
{
NSDictionary dict = (NSDictionary)PropertyListParser.Parse(new FileInfo("test-files/issue49.plist"));
Assert.AreEqual(0, dict.Count);
Assert.Equal(0, dict.Count);
}
[Fact]
public static void TestRealInResourceRule()
{
NSDictionary dict = (NSDictionary)XmlPropertyListParser.Parse(new FileInfo("test-files/ResourceRules.plist"));
Assert.Equal(1, dict.Count);
Assert.True(dict.ContainsKey("weight"));
var weight = dict["weight"].ToObject();
Assert.IsType<double>(weight);
Assert.Equal(10d, (double)weight);
}
[Fact]
public static void RoundtripTest()
{
var expected = File.ReadAllText(@"test-files\Roundtrip.plist");
var value = XmlPropertyListParser.Parse(new FileInfo(@"test-files\Roundtrip.plist"));
var actual = value.ToXmlPropertyList();
Assert.Equal(expected, actual, false, true);
}
}
}

View File

@@ -0,0 +1,95 @@
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
{
/// <summary>
/// Tests the addition of a .NET object to the NSArray
/// </summary>
[Fact]
public void AddAndContainsObjectTest()
{
NSArray array = new NSArray();
array.Add(1);
Assert.True(array.Contains(1));
Assert.False(array.Contains(2));
}
/// <summary>
/// Tests the <see cref="NSArray.IndexOf(object)"/> method for .NET objects.
/// </summary>
[Fact]
public void IndexOfTest()
{
NSArray array = new NSArray();
array.Add(1);
array.Add("test");
Assert.Equal(0, array.IndexOf(1));
Assert.Equal(1, array.IndexOf("test"));
}
/// <summary>
/// Tests the <see cref="NSArray.Insert(int, object)"/> method for a
/// .NET object.
/// </summary>
[Fact]
public void InsertTest()
{
NSArray array = new NSArray();
array.Add(0);
array.Add(1);
array.Add(2);
array.Insert(1, "test");
Assert.Equal(4, array.Count);
Assert.Equal("test", array.ObjectAtIndex(1).ToObject());
}
/// <summary>
/// Tests the <see cref="NSArray.Remove(object)"/> method for a .NET object.
/// </summary>
[Fact]
public void RemoveTest()
{
NSArray array = new NSArray();
array.Add(0);
Assert.False(array.Remove((object)1));
Assert.True(array.Remove((object)0));
Assert.Equal(0, array.Count);
}
/// <summary>
/// Tests the <see cref="NSArray.GetEnumerator"/> method.
/// </summary>
[Fact]
public void EnumeratorTest()
{
NSArray array = new NSArray();
array.Add(0);
array.Add(1);
var enumerator = array.GetEnumerator();
Assert.Null(enumerator.Current);
Assert.True(enumerator.MoveNext());
Assert.Equal(new NSNumber(0), enumerator.Current);
Assert.True(enumerator.MoveNext());
Assert.Equal(new NSNumber(1), enumerator.Current);
Assert.False(enumerator.MoveNext());
}
}
}

View File

@@ -0,0 +1,31 @@
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 NSDateTests
{
[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);
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);
Assert.Equal(expected, actual);
}
}
}

View File

@@ -0,0 +1,76 @@
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
{
public class NSNumberTests
{
[Fact]
public static void NSNumberConstructorTest()
{
var number = new NSNumber("10032936613", NSNumber.INTEGER);
Assert.Equal(NSNumber.INTEGER, number.GetNSNumberType());
Assert.Equal(10032936613, number.ToObject());
}
// The tests below make sure the numbers are being parsed correctly, and do not depend on the culture info
// being set. Especially, decimal point may vary between cultures and we don't want to take a dependency on that
// The value being used comes seen in a real property list:
// <key>TimeZoneOffsetFromUTC</key>
// <real>7200.000000</real>
#if !NETCORE
[Fact]
[UseCulture("en-US")]
public static void ParseNumberEnTest()
{
var number = new NSNumber("7200.000001");
Assert.True(number.isReal());
Assert.Equal(7200.000001d, number.ToDouble());
}
[Fact]
[UseCulture("nl-BE")]
public static void ParseNumberNlTest()
{
// As seen in a real property list:
// <key>TimeZoneOffsetFromUTC</key>
// <real>7200.000000</real>
var number = new NSNumber("7200.000001");
Assert.True(number.isReal());
Assert.Equal(7200.000001d, number.ToDouble());
}
[Fact]
[UseCulture("en-US")]
public static void ParseNumberEnTest2()
{
// As seen in a real property list:
// <key>TimeZoneOffsetFromUTC</key>
// <real>7200.000000</real>
var number = new NSNumber("7200.000000", NSNumber.REAL);
Assert.True(number.isReal());
Assert.Equal(7200d, number.ToDouble());
}
[Fact]
[UseCulture("nl-BE")]
public static void ParseNumberNlTest2()
{
// As seen in a real property list:
// <key>TimeZoneOffsetFromUTC</key>
// <real>7200.000000</real>
var number = new NSNumber("7200.000000", NSNumber.REAL);
Assert.True(number.isReal());
Assert.Equal(7200d, number.ToDouble());
}
#endif
}
}

View File

@@ -24,19 +24,18 @@
// SOFTWARE.
using System;
using System.IO;
using NUnit.Framework;
using Xunit;
using Claunia.PropertyList;
using System.Collections.Generic;
namespace plistcil.test
{
[TestFixture]
public static class ParseTest
{
/**
* Test the xml reader/writer
*/
[Test]
[Fact]
public static void TestXml()
{
// Parse an example plist file
@@ -47,7 +46,8 @@ namespace plistcil.test
Assert.True(d.Count == 5);
Assert.True(((NSString)d.ObjectForKey("keyA")).ToString().Equals("valueA"));
Assert.True(((NSString)d.ObjectForKey("key&B")).ToString().Equals("value&B"));
Assert.True(((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 9, 21, 30, DateTimeKind.Utc)));
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");
@@ -66,7 +66,7 @@ namespace plistcil.test
/**
* Test the binary reader/writer.
*/
[Test]
[Fact]
public static void TestBinary()
{
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1.plist"));
@@ -82,7 +82,7 @@ namespace plistcil.test
* NSSets are not yet supported in reading/writing, as binary property list format v1+ is required.
*/
/*
[Test]
[Fact]
public static void TestSet()
{
NSSet s = new NSSet();
@@ -104,7 +104,7 @@ namespace plistcil.test
Assert.True(ParsedRoot.Equals(dict));
}*/
[Test]
[Fact]
public static void TestASCII()
{
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1-ascii.plist"));
@@ -112,7 +112,11 @@ namespace plistcil.test
Assert.True(d.Count == 5);
Assert.True(((NSString)d.ObjectForKey("keyA")).ToString().Equals("valueA"));
Assert.True(((NSString)d.ObjectForKey("key&B")).ToString().Equals("value&B"));
Assert.True(((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 9, 21, 30, DateTimeKind.Utc)));
var actualDate = (NSDate)d.ObjectForKey("date");
var 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 }));
NSArray a = (NSArray)d.ObjectForKey("array");
@@ -123,7 +127,7 @@ namespace plistcil.test
Assert.True(a.ObjectAtIndex(3).Equals(new NSString("3.14159")));
}
[Test]
[Fact]
public static void TestGnuStepASCII()
{
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test1-ascii-gnustep.plist"));
@@ -131,7 +135,7 @@ namespace plistcil.test
Assert.True(d.Count == 5);
Assert.True(((NSString)d.ObjectForKey("keyA")).ToString().Equals("valueA"));
Assert.True(((NSString)d.ObjectForKey("key&B")).ToString().Equals("value&B"));
Assert.True(((NSDate)d.ObjectForKey("date")).Date.Equals(new DateTime(2011, 11, 28, 9, 21, 30, DateTimeKind.Utc)));
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");
@@ -142,7 +146,7 @@ namespace plistcil.test
Assert.True(a.ObjectAtIndex(3).Equals(new NSNumber(3.14159)));
}
[Test]
[Fact]
public static void TestASCIIWriting()
{
FileInfo inf = new FileInfo("test-files/test1.plist");
@@ -158,7 +162,7 @@ namespace plistcil.test
Assert.True(y.Equals(z));
}
[Test]
[Fact]
public static void TestGnuStepASCIIWriting()
{
FileInfo inf = new FileInfo("test-files/test1.plist");
@@ -169,7 +173,7 @@ namespace plistcil.test
Assert.True(x.Equals(y));
}
[Test]
[Fact]
public static void TestWrap()
{
bool bl = true;
@@ -182,7 +186,6 @@ namespace plistcil.test
DateTime date = new DateTime();
string strg = "Hello World";
byte[] bytes = new byte[] { (byte)0x00, (byte)0xAF, (byte)0xAF };
DirectoryInfo netObject = new DirectoryInfo(Environment.CurrentDirectory);
Object[] array = new Object[] { bl, byt, shrt, i, lng, flt, dbl, date, strg, bytes };
int[] array2 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3000 };
List<Object> list = new List<Object>(array);
@@ -249,8 +252,6 @@ namespace plistcil.test
objArray = (Object[])WrappedO.ToObject();
Assert.True(objArray.Length == array.Length);
Assert.True(NSObject.Wrap((Object)netObject).GetType().Equals(typeof(NSData)));
WrappedO = NSObject.Wrap((Object)map);
Assert.True(WrappedO.GetType().Equals(typeof(NSDictionary)));
NSDictionary dict = (NSDictionary)WrappedO;
@@ -283,6 +284,16 @@ namespace plistcil.test
return false;
}
}
[Fact]
public static void testAsciiUtf8CharactersInQuotedString()
{
NSObject x = PropertyListParser.Parse(new FileInfo("test-files/test-ascii-utf8.plist"));
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());
}
}
}

View File

@@ -1,51 +0,0 @@
// plist-cil - An open source library to parse and generate property lists for .NET
// Copyright (C) 2015 Natalia Portillo
//
// This code is based on:
// plist - An open source library to parse and generate property lists
// Copyright (C) 2014 Daniel Dreibrodt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("plist-cil.test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Claunia.com")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("© Claunia.com")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@@ -0,0 +1,23 @@
using Claunia.PropertyList;
using Xunit;
using System.IO;
namespace plistcil.test
{
public class PropertyListParserTests
{
[Fact]
public static void ParseEmptyStreamTest()
{
Assert.Throws<PropertyListFormatException>(() => ParseEmptyStreamTestDelegate());
}
static void ParseEmptyStreamTestDelegate()
{
using (MemoryStream stream = new MemoryStream())
{
PropertyListParser.Parse(stream);
}
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using Xunit.Sdk;
/// <summary>
/// Apply this attribute to your test method to replace the
/// <see cref="Thread.CurrentThread" /> <see cref="CultureInfo.CurrentCulture" /> and
/// <see cref="CultureInfo.CurrentUICulture" /> with another culture.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class UseCultureAttribute : BeforeAfterTestAttribute
{
readonly Lazy<CultureInfo> culture;
readonly Lazy<CultureInfo> uiCulture;
CultureInfo originalCulture;
CultureInfo originalUICulture;
/// <summary>
/// Replaces the culture and UI culture of the current thread with
/// <paramref name="culture" />
/// </summary>
/// <param name="culture">The name of the culture.</param>
/// <remarks>
/// <para>
/// This constructor overload uses <paramref name="culture" /> for both
/// <see cref="Culture" /> and <see cref="UICulture" />.
/// </para>
/// </remarks>
public UseCultureAttribute(string culture)
: this(culture, culture) { }
/// <summary>
/// Replaces the culture and UI culture of the current thread with
/// <paramref name="culture" /> and <paramref name="uiCulture" />
/// </summary>
/// <param name="culture">The name of the culture.</param>
/// <param name="uiCulture">The name of the UI culture.</param>
public UseCultureAttribute(string culture, string uiCulture)
{
this.culture = new Lazy<CultureInfo>(() => new CultureInfo(culture));
this.uiCulture = new Lazy<CultureInfo>(() => new CultureInfo(uiCulture));
}
/// <summary>
/// Gets the culture.
/// </summary>
public CultureInfo Culture { get { return culture.Value; } }
/// <summary>
/// Gets the UI culture.
/// </summary>
public CultureInfo UICulture { get { return uiCulture.Value; } }
/// <summary>
/// Stores the current <see cref="Thread.CurrentPrincipal" />
/// <see cref="CultureInfo.CurrentCulture" /> and <see cref="CultureInfo.CurrentUICulture" />
/// and replaces them with the new cultures defined in the constructor.
/// </summary>
/// <param name="methodUnderTest">The method under test</param>
public override void Before(MethodInfo methodUnderTest)
{
#if NETCORE
originalCulture = CultureInfo.CurrentCulture;
originalUICulture = CultureInfo.CurrentUICulture;
CultureInfo.CurrentCulture = Culture;
CultureInfo.CurrentUICulture = Culture;
#else
originalCulture = Thread.CurrentThread.CurrentCulture;
originalUICulture = Thread.CurrentThread.CurrentUICulture;
Thread.CurrentThread.CurrentCulture = Culture;
Thread.CurrentThread.CurrentUICulture = UICulture;
#endif
}
/// <summary>
/// Restores the original <see cref="CultureInfo.CurrentCulture" /> and
/// <see cref="CultureInfo.CurrentUICulture" /> to <see cref="Thread.CurrentPrincipal" />
/// </summary>
/// <param name="methodUnderTest">The method under test</param>
public override void After(MethodInfo methodUnderTest)
{
#if NETCORE
CultureInfo.CurrentCulture = originalCulture;
CultureInfo.CurrentUICulture = originalUICulture;
#else
Thread.CurrentThread.CurrentCulture = originalCulture;
Thread.CurrentThread.CurrentUICulture = originalUICulture;
#endif
}
}

View File

@@ -1,47 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{36AD4394-6A31-465F-BE8E-E4806A89CC38}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>plistcil.test</RootNamespace>
<AssemblyName>plist-cil.test</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<ReleaseVersion>1.13</ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<TargetFramework>netcoreapp1.0</TargetFramework>
<TargetFrameworks>netcoreapp1.0;net45</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp1.0'">
<DefineConstants>NETCOREAPP1_0;NETCORE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ParseTest.cs" />
<Compile Include="IssueTest.cs" />
<ProjectReference Include="..\plist-cil\plist-cil.csproj" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<None Include="packages.config" />
<None Include="..\test-files\test1-ascii-gnustep.plist">
<Link>test-files\test1-ascii-gnustep.plist</Link>
<Gettext-ScanForTranslations>False</Gettext-ScanForTranslations>
@@ -112,14 +90,21 @@
<Gettext-ScanForTranslations>False</Gettext-ScanForTranslations>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\test-files\test-ascii-utf8.plist">
<Link>test-files\test-ascii-utf8.plist</Link>
<Gettext-ScanForTranslations>False</Gettext-ScanForTranslations>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="test-files\ResourceRules.plist">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="test-files\Roundtrip.plist">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\plist-cil\plist-cil.csproj">
<Project>{5EA40CD5-CB98-4FD5-8628-3B399EACB38B}</Project>
<Name>plist-cil</Name>
</ProjectReference>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<ItemGroup>
<Folder Include="test-files\" />
</ItemGroup>
</Project>
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>weight</key>
<real>10</real>
</dict>
</plist>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict>
<key>PkgInfo</key>
<data>
n57qDP4tZfLD1rCS43W0B4LQjzE=
</data>
<key>icon.png</key>
<data>
EUOeOW/HpmiAZeEGzJm8j3hE6vo=
</data>
</dict>
<key>files2</key>
<dict>
<key>PkgInfo</key>
<data>
n57qDP4tZfLD1rCS43W0B4LQjzE=
</data>
<key>icon.png</key>
<data>
EUOeOW/HpmiAZeEGzJm8j3hE6vo=
</data>
</dict>
<key>rules</key>
<dict>
<key>.*</key>
<true/>
<key>Info.plist</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>ResourceRules.plist</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>100</real>
</dict>
</dict>
<key>rules2</key>
<dict>
<key>.*</key>
<true/>
<key>Info.plist</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>ResourceRules.plist</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>100</real>
</dict>
<key>^(Frameworks|SharedFrameworks|Plugins|Plug-ins|XPCServices|Helpers|MacOS)/</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>0.0</real>
</dict>
<key>^[^/]+$</key>
<dict>
<key>top</key>
<true/>
<key>weight</key>
<real>0.0</real>
</dict>
</dict>
</dict>
</plist>

View File

@@ -79,7 +79,8 @@ namespace Claunia.PropertyList
public static NSObject Parse(Stream fs)
{
byte[] buf = PropertyListParser.ReadAll(fs);
fs.Close();
// Don't close the stream - that would be the responisibility of code that class
// Parse
return Parse(buf);
}
@@ -91,7 +92,7 @@ namespace Claunia.PropertyList
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
public static NSObject Parse(byte[] bytes)
{
ASCIIPropertyListParser parser = new ASCIIPropertyListParser(bytes);
ASCIIPropertyListParser parser = new ASCIIPropertyListParser(Encoding.UTF8.GetString(bytes).ToCharArray());
return parser.Parse();
}
@@ -234,7 +235,7 @@ namespace Claunia.PropertyList
/**
* Property list source data
*/
byte[] data;
char[] data;
/**
* Current parsing index
*/
@@ -252,7 +253,7 @@ namespace Claunia.PropertyList
/// Creates a new parser for the given property list content.
/// </summary>
/// <param name="propertyListContent">The content of the property list that is to be parsed.</param>
ASCIIPropertyListParser(byte[] propertyListContent)
ASCIIPropertyListParser(char[] propertyListContent)
{
data = propertyListContent;
}
@@ -310,7 +311,7 @@ namespace Claunia.PropertyList
for (int i = 1; i < expectedSymbols.Length; i++)
excString += " or '" + expectedSymbols[i] + "'";
excString += " but found '" + (char)data[index] + "'";
excString += " but found '" + data[index] + "'";
throw new FormatException(String.Format("{0} at {1}", excString, index));
}
}
@@ -406,7 +407,7 @@ namespace Claunia.PropertyList
string s = "";
while (!Accept(symbols))
{
s += (char)data[index];
s += data[index];
Skip();
}
return s;
@@ -422,7 +423,7 @@ namespace Claunia.PropertyList
String s = "";
while (!Accept(symbol))
{
s += (char)data[index];
s += data[index];
Skip();
}
return s;
@@ -437,6 +438,9 @@ namespace Claunia.PropertyList
public NSObject Parse()
{
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);
SkipWhitespacesAndComments();
Expect(DICTIONARY_BEGIN_TOKEN, ARRAY_BEGIN_TOKEN, COMMENT_BEGIN_TOKEN);
try
@@ -459,19 +463,19 @@ namespace Claunia.PropertyList
{
switch (data[index])
{
case (byte)ARRAY_BEGIN_TOKEN:
case ARRAY_BEGIN_TOKEN:
{
return ParseArray();
}
case (byte)DICTIONARY_BEGIN_TOKEN:
case DICTIONARY_BEGIN_TOKEN:
{
return ParseDictionary();
}
case (byte)DATA_BEGIN_TOKEN:
case DATA_BEGIN_TOKEN:
{
return ParseData();
}
case (byte)QUOTEDSTRING_BEGIN_TOKEN:
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
@@ -686,7 +690,7 @@ namespace Claunia.PropertyList
//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))
{
quotedString += (char)data[index];
quotedString += data[index];
if (Accept(QUOTEDSTRING_ESCAPE_TOKEN))
{
unescapedBackslash = !(data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash);
@@ -715,11 +719,12 @@ namespace Claunia.PropertyList
/// <param name="s">The escaped string according to the ASCII property list format, without leading and trailing quotation marks.</param>
/// <exception cref="ArgumentException">If the en-/decoder for the UTF-8 or ASCII encoding could not be loaded</exception>
/// <exception cref="EncoderFallbackException">If the string is encoded neither in ASCII nor in UTF-8</exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public static string ParseQuotedString(string s)
{
List<byte> strBytes = new List<byte>();
CharEnumerator c = s.GetEnumerator();
var characters = (IEnumerable<char>)s.ToCharArray();
var c = characters.GetEnumerator();
while (c.MoveNext())
{
@@ -734,8 +739,7 @@ namespace Claunia.PropertyList
}
default:
{ //a normal ASCII char
strBytes.Add((byte)0);
strBytes.Add((byte)c.Current);
strBytes.AddRange(Encoding.BigEndianUnicode.GetBytes(new[] { c.Current }));
break;
}
}
@@ -752,7 +756,7 @@ namespace Claunia.PropertyList
//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
@@ -765,7 +769,7 @@ namespace Claunia.PropertyList
/// <returns>The unescaped character as a string.</returns>
/// <param name="iterator">The string character iterator pointing to the first character after the backslash</param>
/// <exception cref="EncoderFallbackException">If an invalid Unicode or ASCII escape sequence is found.</exception>
private static string ParseEscapedSequence(CharEnumerator iterator)
private static string ParseEscapedSequence(IEnumerator<char> iterator)
{
iterator.MoveNext();
char c = iterator.Current;

View File

@@ -23,6 +23,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Diagnostics;
using System.Text;
using System.IO;
@@ -42,38 +43,26 @@ namespace Claunia.PropertyList
/// @author Natalia Portillo
public class BinaryPropertyListParser
{
int majorVersion, minorVersion;
/// <summary>
/// Major version of the property list format
/// </summary>
int majorVersion;
/// <summary>
/// Minor version of the property list format
/// </summary>
int minorVersion;
/// <summary>
/// Property list in bytes
/// </summary>
byte[] bytes;
/// <summary>
/// Length of an offset definition in bytes
/// </summary>
int offsetSize;
/// <summary>
/// Length of an object reference in bytes
/// </summary>
int objectRefSize;
/// <summary>
/// Number of objects stored in this property list
/// </summary>
int numObjects;
/// <summary>
/// Reference to the top object of the property list
/// </summary>
int topObject;
/// <summary>
/// Offset of the offset table from the beginning of the file
/// </summary>
int offsetTableOffset;
/// <summary>
/// The table holding the information at which offset each object is found
/// </summary>
@@ -126,6 +115,7 @@ namespace Claunia.PropertyList
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.");
}
@@ -135,16 +125,11 @@ namespace Claunia.PropertyList
*/
byte[] trailer = CopyOfRange(bytes, bytes.Length - 32, bytes.Length);
//6 null bytes (index 0 to 5)
offsetSize = (int)ParseUnsignedInt(trailer, 6, 7);
//System.Console.WriteLine("offsetSize: "+offsetSize);
int offsetSize = (int)ParseUnsignedInt(trailer, 6, 7);
objectRefSize = (int)ParseUnsignedInt(trailer, 7, 8);
//System.Console.WriteLine("objectRefSize: "+objectRefSize);
numObjects = (int)ParseUnsignedInt(trailer, 8, 16);
//System.Console.WriteLine("numObjects: "+numObjects);
topObject = (int)ParseUnsignedInt(trailer, 16, 24);
//System.Console.WriteLine("topObject: "+topObject);
offsetTableOffset = (int)ParseUnsignedInt(trailer, 24, 32);
//System.Console.WriteLine("offsetTableOffset: "+offsetTableOffset);
int numObjects = (int)ParseUnsignedInt(trailer, 8, 16);
int topObject = (int)ParseUnsignedInt(trailer, 16, 24);
int offsetTableOffset = (int)ParseUnsignedInt(trailer, 24, 32);
/*
* Handle offset table
@@ -155,9 +140,6 @@ namespace Claunia.PropertyList
{
byte[] offsetBytes = CopyOfRange(bytes, offsetTableOffset + i * offsetSize, offsetTableOffset + (i + 1) * offsetSize);
offsetTable[i] = (int)ParseUnsignedInt(offsetBytes);
/*System.Console.Write("Offset for Object #"+i+" is "+offsetTable[i]+" [");
foreach(byte b: in ffsetBytes) System.Console.Write(Convert.ToString((int)b, 16))+" ");
System.Console.WriteLine("]");*/
}
return ParseObject(topObject);
@@ -173,7 +155,8 @@ namespace Claunia.PropertyList
{
//Read all bytes into a list
byte[] buf = PropertyListParser.ReadAll(fs);
fs.Close();
// Don't close the stream - that would be the responisibility of code that class
// Parse
return Parse(buf);
}
@@ -185,22 +168,13 @@ namespace Claunia.PropertyList
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
public static NSObject Parse(FileInfo f)
{
// While on Java, heap size is limited by the JVM, on .NET the heap size is dynamically allocated using all
// available RAM+swap. There is a function to check if that allocation can succeed, but works in 16MiB pieces,
// far bigger than any known PropertyList. And even then, paging would allow to work with insanely sized PropertyLists.
// Therefor, the checks in .NET (System.Runtime.MemoryFailPoint) are not worth the effort.
// Rest of calls to Java's Runtime.getRuntime().freeMemory() will not be commented but completely removed.
/*
if (f.length() > Runtime.getRuntime().freeMemory()) {
throw new OutOfMemoryError("To little heap space available! Wanted to read " + f.length() + " bytes, but only " + Runtime.getRuntime().freeMemory() + " are available.");
}*/
return Parse(f.OpenRead());
}
/// <summary>
/// Parses an object inside the currently parsed binary property list.
/// For the format specification check
/// <a href="http://www.opensource.apple.com/source/CF/CF-744/CFBinaryPList.c">
/// <a href="http://www.opensource.apple.com/source/CF/CF-855.17/CFBinaryPList.c">
/// Apple's binary property list parser implementation</a>.
/// </summary>
/// <returns>The parsed object.</returns>
@@ -237,19 +211,19 @@ namespace Claunia.PropertyList
case 0xC:
{
//URL with no base URL (v1.0 and later)
//TODO
//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
//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
//TODO Implement binary UUID parsing (not yet even implemented in Core Foundation as of revision 855.17)
break;
}
case 0xF:
@@ -284,62 +258,74 @@ namespace Claunia.PropertyList
case 0x4:
{
//Data
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int dataoffset = lenAndoffset[1];
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int length = lengthAndOffset[0];
int dataoffset = lengthAndOffset[1];
return new NSData(CopyOfRange(bytes, offset + dataoffset, offset + dataoffset + length));
}
case 0x5:
{
//ASCII String
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int stroffset = lenAndoffset[1];
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int length = lengthAndOffset[0]; //Each character is 1 byte
int stroffset = lengthAndOffset[1];
return new NSString(CopyOfRange(bytes, offset + stroffset, offset + stroffset + length), "ASCII");
}
case 0x6:
{
//UTF-16-BE String
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int stroffset = lenAndoffset[1];
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int length = lengthAndOffset[0];
int stroffset = lengthAndOffset[1];
//length is String length -> to get byte length multiply by 2, as 1 character takes 2 bytes in UTF-16
//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(CopyOfRange(bytes, offset + stroffset, offset + stroffset + length), "UTF-16BE");
}
case 0x7:
{
//UTF-8 string (v1.0 and later)
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int strOffset = lengthAndOffset[1];
int characters = lengthAndOffset[0];
//UTF-8 characters can have variable length, so we need to calculate the byte length dynamically
//by reading the UTF-8 characters one by one
int length = CalculateUtf8StringLength(bytes, offset + strOffset, characters);
return new NSString(CopyOfRange(bytes, offset + strOffset, offset + strOffset + length), "UTF-8");
}
case 0x8:
{
//UID
//UID (v1.0 and later)
int length = objInfo + 1;
return new UID(obj.ToString(), CopyOfRange(bytes, offset + 1, offset + 1 + length));
}
case 0xA:
{
//Array
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int arrayoffset = lenAndoffset[1];
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int length = lengthAndOffset[0];
int arrayOffset = lengthAndOffset[1];
NSArray array = new NSArray(length);
for (int i = 0; i < length; i++)
{
int objRef = (int)ParseUnsignedInt(CopyOfRange(bytes,
offset + arrayoffset + i * objectRefSize,
offset + arrayoffset + (i + 1) * objectRefSize));
array.SetValue(i, ParseObject(objRef));
offset + arrayOffset + i * objectRefSize,
offset + arrayOffset + (i + 1) * objectRefSize));
array.Add(ParseObject(objRef));
}
return array;
}
case 0xB:
{
//Ordered set
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int contentOffset = lenAndoffset[1];
//Ordered set (v1.0 and later)
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int length = lengthAndOffset[0];
int contentOffset = lengthAndOffset[1];
NSSet set = new NSSet(true);
for (int i = 0; i < length; i++)
@@ -353,10 +339,10 @@ namespace Claunia.PropertyList
}
case 0xC:
{
//Set
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int contentOffset = lenAndoffset[1];
//Set (v1.0 and later)
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int length = lengthAndOffset[0];
int contentOffset = lengthAndOffset[1];
NSSet set = new NSSet();
for (int i = 0; i < length; i++)
@@ -371,9 +357,9 @@ namespace Claunia.PropertyList
case 0xD:
{
//Dictionary
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int contentOffset = lenAndoffset[1];
int[] lengthAndOffset = ReadLengthAndOffset(objInfo, offset);
int length = lengthAndOffset[0];
int contentOffset = lengthAndOffset[1];
//System.out.println("Parsing dictionary #"+obj);
NSDictionary dict = new NSDictionary();
@@ -393,7 +379,7 @@ namespace Claunia.PropertyList
}
default:
{
Console.WriteLine("WARNING: The given binary property list contains an object of unknown type (" + objType + ")");
Debug.WriteLine("WARNING: The given binary property list contains an object of unknown type (" + objType + ")");
break;
}
}
@@ -408,22 +394,22 @@ namespace Claunia.PropertyList
/// <param name="offset">Offset in the byte array at which the object is located.</param>
int[] ReadLengthAndOffset(int objInfo, int offset)
{
int length = objInfo;
int stroffset = 1;
int lengthValue = objInfo;
int offsetValue = 1;
if (objInfo == 0xF)
{
int int_type = bytes[offset + 1];
int intType = (int_type & 0xF0) >> 4;
if (intType != 0x1)
{
Console.WriteLine("BinaryPropertyListParser: Length integer has an unexpected type" + intType + ". Attempting to parse anyway...");
Debug.WriteLine("BinaryPropertyListParser: Length integer has an unexpected type" + intType + ". Attempting to parse anyway...");
}
int intInfo = int_type & 0x0F;
int intLength = (int)Math.Pow(2, intInfo);
stroffset = 2 + intLength;
offsetValue = 2 + intLength;
if (intLength < 3)
{
length = (int)ParseUnsignedInt(CopyOfRange(bytes, offset + 2, offset + 2 + intLength));
lengthValue = (int)ParseUnsignedInt(CopyOfRange(bytes, offset + 2, offset + 2 + intLength));
}
else
{
@@ -435,10 +421,71 @@ namespace Claunia.PropertyList
litEBigInteger[i] = bigEBigInteger[j];
litEBigInteger[litEBigInteger.Length - 1] = (byte)0x00; // Be sure to get unsigned BigInteger
length = (int)new System.Numerics.BigInteger(litEBigInteger);
lengthValue = (int)new System.Numerics.BigInteger(litEBigInteger);
}
}
return new []{ length, stroffset };
return new []{ lengthValue, offsetValue };
}
/// <summary>
/// Calculates the length in bytes of the UTF-8 string.
/// </summary>
/// <returns>The UTF-8 string length.</returns>
/// <param name="bytes">Array containing the UTF-8 string.</param>
/// <param name="offset">Offset in the array where the UTF-8 string resides.</param>
/// <param name="numCharacters">How many UTF-8 characters are in the string.</param>
int CalculateUtf8StringLength(byte[] bytes, int offset, int numCharacters)
{
int length = 0;
for (int i = 0; i < numCharacters; i++)
{
int tempOffset = offset + length;
if (bytes.Length <= tempOffset)
{
//WARNING: Invalid UTF-8 string, fall back to length = number of characters
return numCharacters;
}
if (bytes[tempOffset] < 0x80)
{
length++;
}
if (bytes[tempOffset] < 0xC2)
{
//Invalid value (marks continuation byte), fall back to length = number of characters
return numCharacters;
}
else if (bytes[tempOffset] < 0xE0)
{
if ((bytes[tempOffset + 1] & 0xC0) != 0x80)
{
//Invalid continuation byte, fall back to length = number of characters
return numCharacters;
}
length += 2;
}
else if (bytes[tempOffset] < 0xF0)
{
if ((bytes[tempOffset + 1] & 0xC0) != 0x80
|| (bytes[tempOffset + 2] & 0xC0) != 0x80)
{
//Invalid continuation byte, fall back to length = number of characters
return numCharacters;
}
length += 3;
}
else if (bytes[tempOffset] < 0xF5)
{
if ((bytes[tempOffset + 1] & 0xC0) != 0x80
|| (bytes[tempOffset + 2] & 0xC0) != 0x80
|| (bytes[tempOffset + 3] & 0xC0) != 0x80)
{
//Invalid continuation byte, fall back to length = number of characters
return numCharacters;
}
length += 4;
}
}
return length;
}
/// <summary>

View File

@@ -24,7 +24,9 @@
// SOFTWARE.
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Claunia.PropertyList
{
@@ -59,6 +61,21 @@ namespace Claunia.PropertyList
/// </summary>
public const int VERSION_20 = 20;
/// <summary>
/// Gets or sets a value indicating whether two equivalent objects should be serialized once in the binary property list file, or whether
/// the value should be stored multiple times in the binary property list file. The default is <see langword="false"/>.
/// </summary>
/// <remarks>
/// In most scenarios, you want this to be <see langword="true"/>, as it reduces the size of the binary proeprty list file. However,
/// by default, the Apple tools do not seem to implement this optimization, so set this value to <see langword="false"/> if you
/// want to maintain binary compatibility with the Apple tools.
/// </remarks>
public bool ReuseObjectIds
{
get;
set;
}
/// <summary>
/// Finds out the minimum binary property list format version that
/// can be used to save the given NSObject tree.
@@ -115,9 +132,10 @@ namespace Claunia.PropertyList
/// <exception cref="IOException"></exception>
public static void Write(FileInfo file, NSObject root)
{
FileStream fous = file.OpenWrite();
Write(fous, root);
fous.Close();
using (FileStream fous = file.OpenWrite())
{
Write(fous, root);
}
}
/// <summary>
@@ -162,7 +180,7 @@ namespace Claunia.PropertyList
long count;
// map from object to its ID
Dictionary<NSObject, int> idMap = new Dictionary<NSObject, int>();
Collection<NSObject> idMap = new Collection<NSObject>(); //(new IdentityEqualityComparer<NSObject>());
int idSizeInBytes;
/// <summary>
@@ -170,43 +188,43 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="outStr">The output stream into which the binary property list will be written</param>
/// <exception cref="IOException">If an error occured while writing to the stream</exception>
BinaryPropertyListWriter(Stream outStr)
public BinaryPropertyListWriter(Stream outStr)
{
outStream = outStr;
}
BinaryPropertyListWriter(Stream outStr, int version)
public BinaryPropertyListWriter(Stream outStr, int version)
{
this.version = version;
outStream = outStr;
}
void Write(NSObject root)
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)
{
case VERSION_00:
{
Write(new []{ (byte)'0', (byte)'0' });
Write(new[] { (byte)'0', (byte)'0' });
break;
}
case VERSION_10:
{
Write(new []{ (byte)'1', (byte)'0' });
Write(new[] { (byte)'1', (byte)'0' });
break;
}
case VERSION_15:
{
Write(new []{ (byte)'1', (byte)'5' });
Write(new[] { (byte)'1', (byte)'5' });
break;
}
case VERSION_20:
{
Write(new []{ (byte)'2', (byte)'0' });
Write(new[] { (byte)'2', (byte)'0' });
break;
}
}
@@ -220,10 +238,10 @@ namespace Claunia.PropertyList
long[] offsets = new long[idMap.Count];
// write each object, save offset
foreach (KeyValuePair<NSObject, int> entry in idMap)
for (int i = 0; i < idMap.Count; i++)
{
NSObject obj = entry.Key;
int id = entry.Value;
NSObject obj = idMap[i];
int id = i;
offsets[id] = count;
if (obj == null)
{
@@ -255,8 +273,7 @@ namespace Claunia.PropertyList
// number of objects
WriteLong(idMap.Count);
// top object
int rootID;
idMap.TryGetValue(root, out rootID);
int rootID = idMap.IndexOf(root);
WriteLong(rootID);
// offset table offset
WriteLong(offsetTableOffset);
@@ -267,17 +284,60 @@ namespace Claunia.PropertyList
internal void AssignID(NSObject obj)
{
if (!idMap.ContainsKey(obj))
// If binary compatibility with the Apple format is required,
// UID, NSArray and NSString objects are assigned a new ID,
// even if they already exist in the file.
if (!this.ReuseObjectIds && (obj is UID || obj is NSNumber || obj is NSArray))
{
idMap.Add(obj, idMap.Count);
idMap.Add(obj);
}
else if (!this.ReuseObjectIds && obj is NSString && !IsSerializationPrimitive((NSString)obj))
{
idMap.Add(obj);
}
else if (!idMap.Contains(obj))
{
idMap.Add(obj);
}
}
internal bool IsSerializationPrimitive(NSString obj)
{
return obj != null && obj.Content.StartsWith("$") || obj.Content.StartsWith("NS");
}
internal int GetID(NSObject obj)
{
int ID;
idMap.TryGetValue(obj, out ID);
return ID;
if (!this.ReuseObjectIds && obj is UID)
{
var uid = obj as UID;
var first = idMap.OfType<UID>().First(v => NSObject.ArrayEquals(v.Bytes, uid.Bytes));
return idMap.IndexOf(first);
}
else if (!this.ReuseObjectIds && (obj is NSArray || (obj is NSString && !IsSerializationPrimitive((NSString)obj))))
{
int index = -1;
for (int i = 0; i < idMap.Count; i++)
{
if (idMap[i] == obj)
{
index = i;
break;
}
}
if (index == -1)
{
throw new InvalidOperationException();
}
return index;
}
else
{
return idMap.IndexOf(obj);
}
}
static int ComputeIdSizeInBytes(int numberOfIds)
@@ -298,8 +358,8 @@ namespace Claunia.PropertyList
internal void WriteIntHeader(int kind, int value)
{
if (value <= 0)
throw new ArgumentException("value must be greater than 0", "value");
if (value < 0)
throw new ArgumentException("value must be greater than or equal to 0", "value");
if (value < 15)
{

View File

@@ -1,3 +1,47 @@
2017-02-22 Natalia Portillo <claunia@claunia.com>
* Properties/AssemblyInfo.cs:
Removed, no longer needed in .NET Core.
* plist-cil.csproj:
Updated for .NET Core.
* NSNumber.cs:
InvariantCulture seems not to be supported in .NET Core, changed to CurrentCulture.
* plist-cil.nuspec:
Updated version, not sure if needed with .NET Core auto-packaging.
2015-02-25 Natalia Portillo <claunia@claunia.com>
* plist-cil.nuspec:
Added gnustep tag to NuSpec
2015-02-25 Natalia Portillo <claunia@claunia.com>
* plist-cil.nuspec:
Added summary and better description.
2015-02-25 Natalia Portillo <claunia@claunia.com>
* plist-cil.nuspec:
* plist-cil.csproj:
Added NuGet package.
2015-02-24 Natalia Portillo <claunia@claunia.com>
* PropertyListParser.cs:
* ASCIIPropertyListParser.cs:
Sync BOM skipping code with upstream.
* BinaryPropertyListParser.cs:
Sync code with upstream.
Added UTF-8 string decoding on binary property lists.
* plist-cil.csproj:
* Properties/AssemblyInfo.cs:
Bump to 1.14 (upstream r114).
2015-02-20 Natalia Portillo <claunia@claunia.com>
* UID.cs:

139
plist-cil/NSArray.IList.cs Normal file
View File

@@ -0,0 +1,139 @@
// plist-cil - An open source library to parse and generate property lists for .NET
// Copyright (C) 2016 Quamotion
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Claunia.PropertyList
{
partial class NSArray : IList<NSObject>
{
/// <inheritdoc/>
public NSObject this[int index]
{
get
{
return this.array[index];
}
set
{
this.array[index] = value;
}
}
/// <inheritdoc/>
public bool IsReadOnly
{
get
{
return false;
}
}
public void Add(object item)
{
this.Add(NSObject.Wrap(item));
}
/// <inheritdoc/>
public void Add(NSObject item)
{
this.array.Add(item);
}
/// <inheritdoc/>
public void Clear()
{
this.array.Clear();
}
public bool Contains(object item)
{
return this.Contains(NSObject.Wrap(item));
}
/// <inheritdoc/>
public bool Contains(NSObject item)
{
return this.array.Contains(item);
}
/// <inheritdoc/>
public void CopyTo(NSObject[] array, int arrayIndex)
{
this.array.CopyTo(array, arrayIndex);
}
/// <inheritdoc/>
public IEnumerator<NSObject> GetEnumerator()
{
return this.array.GetEnumerator();
}
public int IndexOf(object item)
{
return this.array.IndexOf(NSObject.Wrap(item));
}
/// <inheritdoc/>
public int IndexOf(NSObject item)
{
return this.array.IndexOf(item);
}
public void Insert(int index, object item)
{
this.Insert(index, NSObject.Wrap(item));
}
/// <inheritdoc/>
public void Insert(int index, NSObject item)
{
this.array.Insert(index, item);
}
public bool Remove(object item)
{
return this.Remove(NSObject.Wrap(item));
}
/// <inheritdoc/>
public bool Remove(NSObject item)
{
return this.array.Remove(item);
}
/// <inheritdoc/>
public void RemoveAt(int index)
{
this.array.RemoveAt(index);
}
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return this.array.GetEnumerator();
}
}
}

View File

@@ -23,6 +23,8 @@
// 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
@@ -32,9 +34,9 @@ namespace Claunia.PropertyList
/// </summary>
/// @author Daniel Dreibrodt
/// @author Natalia Portillo
public class NSArray : NSObject
public partial class NSArray : NSObject
{
NSObject[] array;
List<NSObject> array;
/// <summary>
/// Creates an empty array of the given length.
@@ -42,7 +44,7 @@ namespace Claunia.PropertyList
/// <param name="length">The number of elements this array will be able to hold.</param>
public NSArray(int length)
{
array = new NSObject[length];
array = new List<NSObject>(length);
}
/// <summary>
@@ -51,7 +53,7 @@ namespace Claunia.PropertyList
/// <param name="a">The array which should be wrapped by the NSArray.</param>
public NSArray(params NSObject[] a)
{
array = a;
array = new List<NSObject>(a);
}
/// <summary>
@@ -59,6 +61,7 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The object at the given index.</returns>
/// <param name="i">The index of the object.</param>
[Obsolete]
public NSObject ObjectAtIndex(int i)
{
return array[i];
@@ -69,14 +72,10 @@ namespace Claunia.PropertyList
/// The array will be resized.
/// </summary>
/// <param name="i">The index of the object</param>
[Obsolete]
public void Remove(int i)
{
if ((i >= array.Length) || (i < 0))
throw new IndexOutOfRangeException("invalid index:" + i + ";the array length is " + array.Length);
NSObject[] newArray = new NSObject[array.Length - 1];
Array.Copy(array, 0, newArray, 0, i);
Array.Copy(array, i + 1, newArray, i, array.Length - i - 1);
array = newArray;
this.array.RemoveAt(i);
}
/// <summary>
@@ -85,6 +84,7 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="key">The index where to store the object.</param>
/// <param name="value">The object.</param>
[Obsolete]
public void SetValue(int key, Object value)
{
if (value == null)
@@ -97,9 +97,10 @@ namespace Claunia.PropertyList
/// Any changes to the values of this array will also affect the NSArray.
/// </summary>
/// <returns>The actual array represented by this NSArray.</returns>
[Obsolete]
public NSObject[] GetArray()
{
return array;
return array.ToArray();
}
/// <summary>
@@ -110,7 +111,7 @@ namespace Claunia.PropertyList
{
get
{
return array.Length;
return array.Count;
}
}
@@ -120,6 +121,7 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns><c>true</c>, when the object could be found. <c>false</c> otherwise.</returns>
/// <param name="obj">The object to look for.</param>
[Obsolete]
public bool ContainsObject(Object obj)
{
NSObject nso = NSObject.Wrap(obj);
@@ -140,10 +142,11 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The index of the object, if it was found. -1 otherwise.</returns>
/// <param name="obj">The object to look for.</param>
[Obsolete]
public int IndexOfObject(Object obj)
{
NSObject nso = NSObject.Wrap(obj);
for (int i = 0; i < array.Length; i++)
for (int i = 0; i < array.Count; i++)
{
if (array[i].Equals(nso))
{
@@ -161,10 +164,11 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The index of the object, if it was found. -1 otherwise.</returns>
/// <param name="obj">The object to look for.</param>
[Obsolete]
public int IndexOfIdenticalObject(Object obj)
{
NSObject nso = NSObject.Wrap(obj);
for (int i = 0; i < array.Length; i++)
for (int i = 0; i < array.Count; i++)
{
if (array[i] == nso)
{
@@ -180,7 +184,7 @@ namespace Claunia.PropertyList
/// <returns>The value of the highest index in the array.</returns>
public NSObject LastObject()
{
return array[array.Length - 1];
return array[array.Count - 1];
}
/// <summary>
@@ -208,14 +212,14 @@ namespace Claunia.PropertyList
{
if (obj.GetType().Equals(typeof(NSArray)))
{
return ArrayEquals(((NSArray)obj).GetArray(), array);
return ArrayEquals(((NSArray)obj).GetArray(), this.GetArray());
}
else
{
NSObject nso = NSObject.Wrap(obj);
if (nso.GetType().Equals(typeof(NSArray)))
{
return ArrayEquals(((NSArray)nso).GetArray(), array);
return ArrayEquals(((NSArray)nso).GetArray(), this.GetArray());
}
}
return false;
@@ -258,7 +262,7 @@ namespace Claunia.PropertyList
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
outPlist.WriteIntHeader(0xA, array.Length);
outPlist.WriteIntHeader(0xA, array.Count);
foreach (NSObject obj in array)
{
outPlist.WriteID(outPlist.GetID(obj));
@@ -308,7 +312,7 @@ 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.Length; 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)))
@@ -325,7 +329,7 @@ namespace Claunia.PropertyList
array[i].ToASCII(ascii, 0);
}
if (i != array.Length - 1)
if (i != array.Count - 1)
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
@@ -342,7 +346,7 @@ 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.Length; 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)))
@@ -359,7 +363,7 @@ namespace Claunia.PropertyList
array[i].ToASCIIGnuStep(ascii, 0);
}
if (i != array.Length - 1)
if (i != array.Count - 1)
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
@@ -382,10 +386,10 @@ namespace Claunia.PropertyList
if (!(obj is NSArray))
return false;
if (array.Length != ((NSArray)obj).array.Length)
if (array.Count != ((NSArray)obj).array.Count)
return false;
for (int i = 0; i < array.Length; i++)
for (int i = 0; i < array.Count; i++)
if (!array[i].Equals(((NSArray)obj).ObjectAtIndex(i)))
return false;

View File

@@ -65,9 +65,10 @@ namespace Claunia.PropertyList
public NSData(FileInfo file)
{
bytes = new byte[(int)file.Length];
FileStream raf = file.OpenRead();
raf.Read(bytes, 0, (int)file.Length);
raf.Close();
using (FileStream raf = file.OpenRead())
{
raf.Read(bytes, 0, (int)file.Length);
}
}
/// <summary>
@@ -121,7 +122,7 @@ namespace Claunia.PropertyList
/// <returns>The Base64 encoded data as a <c>string</c>.</returns>
public string GetBase64EncodedData()
{
return Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
return Convert.ToBase64String(bytes);
}
/// <summary>
@@ -155,7 +156,7 @@ namespace Claunia.PropertyList
string base64 = GetBase64EncodedData();
foreach (string line in base64.Split('\n'))
{
Indent(xml, level + 1);
Indent(xml, level);
xml.Append(line);
xml.Append(NSObject.NEWLINE);
}
@@ -209,6 +210,16 @@ namespace Claunia.PropertyList
return ArrayEquals(bytes, ((NSData)obj).Bytes);
}
static public explicit operator byte[](NSData value)
{
return value.bytes;
}
static public explicit operator NSData(byte[] value)
{
return new NSData(value);
}
}
}

View File

@@ -38,7 +38,9 @@ namespace Claunia.PropertyList
static readonly DateTime EPOCH = new DateTime(2001, 1, 1, 0, 0, 0, DateTimeKind.Utc);
static readonly string sdfDefault = "yyyy-MM-dd'T'HH:mm:ss'Z'";
// The datetime ends with 'Z', which indicates UTC time. To make sure .NET
// understands the 'Z' character as a timezone, specify the 'K' format string.
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;
@@ -67,9 +69,9 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="date">The date which should be represented.</param>
/// <returns>The string representation of the date.</returns>
static string MakeDateString(DateTime date)
public static string MakeDateString(DateTime date)
{
return date.ToString(sdfDefault);
return date.ToUniversalTime().ToString(sdfDefault);
}
/// <summary>
@@ -201,6 +203,16 @@ namespace Claunia.PropertyList
return equality == 0;
}
static public explicit operator DateTime (NSDate value)
{
return value.date;
}
static public explicit operator NSDate(DateTime value)
{
return new NSDate(value);
}
}
}

View File

@@ -45,12 +45,17 @@ namespace Claunia.PropertyList
{
readonly Dictionary<string, NSObject> dict;
// Maps the keys in this dictionary to their NSString equivalent. Makes sure the NSString
// object remains constant accross calls to AssignIDs and ToBinary
readonly Dictionary<string, NSString> keys;
/// <summary>
/// Creates a new empty NSDictionary.
/// </summary>
public NSDictionary()
{
dict = new Dictionary<string, NSObject>();
keys = new Dictionary<string, NSString>();
}
/// <summary>
@@ -187,7 +192,7 @@ namespace Claunia.PropertyList
if (o.GetType().Equals(typeof(NSString)))
{
NSString str = (NSString)o;
if (str.GetContent().Equals(val))
if (str.Content.Equals(val))
return true;
}
}
@@ -363,9 +368,14 @@ namespace Claunia.PropertyList
internal override void AssignIDs(BinaryPropertyListWriter outPlist)
{
base.AssignIDs(outPlist);
foreach (KeyValuePair<string, NSObject> entry in dict)
{
keys[entry.Key].AssignIDs(outPlist);
}
foreach (KeyValuePair<string, NSObject> entry in dict)
{
new NSString(entry.Key).AssignIDs(outPlist);
entry.Value.AssignIDs(outPlist);
}
}
@@ -375,7 +385,7 @@ namespace Claunia.PropertyList
outPlist.WriteIntHeader(0xD, dict.Count);
foreach (KeyValuePair<String, NSObject> entry in dict)
{
outPlist.WriteID(outPlist.GetID(new NSString(entry.Key)));
outPlist.WriteID(outPlist.GetID(keys[entry.Key]));
}
foreach (KeyValuePair<String, NSObject> entry in dict)
{
@@ -483,6 +493,7 @@ namespace Claunia.PropertyList
public void Add(string key, NSObject value)
{
dict.Add(key, value);
keys.Add(key, new NSString(key));
}
/// <summary>
@@ -511,6 +522,7 @@ namespace Claunia.PropertyList
/// <param name="key">Key.</param>
public bool Remove(string key)
{
keys.Remove(key);
return dict.Remove(key);
}
@@ -529,7 +541,7 @@ namespace Claunia.PropertyList
/// Gets or sets the <see cref="Claunia.PropertyList.NSObject"/> at the specified index.
/// </summary>
/// <param name="index">Index.</param>
public NSObject this [string index]
public NSObject this[string index]
{
get
{
@@ -537,6 +549,11 @@ namespace Claunia.PropertyList
}
set
{
if (!keys.ContainsKey(index))
{
keys.Add(index, new NSString(index));
}
dict[index] = value;
}
}
@@ -574,6 +591,7 @@ namespace Claunia.PropertyList
/// <param name="item">Item.</param>
public void Add(KeyValuePair<string, NSObject> item)
{
keys.Add(item.Key, new NSString(item.Key));
dict.Add(item.Key, item.Value);
}
@@ -582,6 +600,7 @@ namespace Claunia.PropertyList
/// </summary>
public void Clear()
{
keys.Clear();
dict.Clear();
}
@@ -613,6 +632,7 @@ namespace Claunia.PropertyList
/// <returns><c>true</c> if successfully removed, <c>false</c> if not, or if item is not in current instance.</returns>
public bool Remove(KeyValuePair<string, NSObject> item)
{
keys.Remove(item.Key);
return dict.Remove(item.Key);
}

View File

@@ -70,17 +70,36 @@ namespace Claunia.PropertyList
/// <seealso cref="INTEGER"/>
/// <seealso cref="REAL"/>
public NSNumber(byte[] bytes, int type)
{
switch (type)
{
case INTEGER:
doubleValue = longValue = BinaryPropertyListParser.ParseLong(bytes);
break;
case REAL:
doubleValue = BinaryPropertyListParser.ParseDouble(bytes);
longValue = (long)Math.Round(doubleValue);
break;
default:
throw new ArgumentException("Type argument is not valid.");
}
this.type = type;
}
public NSNumber(string text, int type)
{
switch (type)
{
case INTEGER:
{
doubleValue = longValue = BinaryPropertyListParser.ParseLong(bytes);
doubleValue = longValue = long.Parse(text, CultureInfo.InvariantCulture);
break;
}
case REAL:
{
doubleValue = BinaryPropertyListParser.ParseDouble(bytes);
doubleValue = double.Parse(text, CultureInfo.InvariantCulture);
longValue = (long)Math.Round(doubleValue);
break;
}
@@ -103,36 +122,39 @@ namespace Claunia.PropertyList
{
if (text == null)
throw new ArgumentException("The given string is null and cannot be parsed as number.");
try
long l;
double d;
if (text.StartsWith("0x") && long.TryParse("", NumberStyles.HexNumber, CultureInfo.InvariantCulture, out l))
{
long l = long.Parse(text);
doubleValue = longValue = l;
type = INTEGER;
}
catch (Exception)
if (long.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out l))
{
try
doubleValue = longValue = l;
type = INTEGER;
}
else if (double.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out d))
{
doubleValue = d;
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);
if (isTrue || isFalse)
{
doubleValue = double.Parse(text, CultureInfo.InvariantCulture);
longValue = (long)Math.Round(doubleValue);
type = REAL;
type = BOOLEAN;
doubleValue = longValue = boolValue ? 1 : 0;
}
catch (Exception)
else
{
try
{
boolValue = text.ToLower().Equals("true") || text.ToLower().Equals("yes");
if (!boolValue && !(text.ToLower().Equals("false") || text.ToLower().Equals("no")))
{
throw new Exception("not a bool");
}
type = BOOLEAN;
doubleValue = longValue = boolValue ? 1 : 0;
}
catch (Exception)
{
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.");
}
}
}
@@ -337,7 +359,19 @@ namespace Claunia.PropertyList
case REAL:
{
xml.Append("<real>");
xml.Append(ToDouble().ToString(CultureInfo.InvariantCulture));
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
{
xml.Append(ToDouble().ToString(CultureInfo.InvariantCulture));
}
xml.Append("</real>");
break;
}
@@ -545,6 +579,116 @@ namespace Claunia.PropertyList
return false;
}
}
static public explicit operator ulong(NSNumber value)
{
return (ulong)value.longValue;
}
static public explicit operator long(NSNumber value)
{
return value.longValue;
}
static public explicit operator uint(NSNumber value)
{
return (uint)value.longValue;
}
static public explicit operator int(NSNumber value)
{
return (int)value.longValue;
}
static public explicit operator ushort(NSNumber value)
{
return (ushort)value.longValue;
}
static public explicit operator short(NSNumber value)
{
return (short)value.longValue;
}
static public explicit operator byte(NSNumber value)
{
return (byte)value.longValue;
}
static public explicit operator sbyte(NSNumber value)
{
return (sbyte)value.longValue;
}
static public explicit operator double(NSNumber value)
{
return value.doubleValue;
}
static public explicit operator float(NSNumber value)
{
return (float)value.doubleValue;
}
static public explicit operator bool(NSNumber value)
{
return value.boolValue;
}
static public explicit operator NSNumber(ulong value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(long value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(uint value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(int value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(ushort value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(short value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(byte value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(sbyte value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(double value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(float value)
{
return new NSNumber(value);
}
static public explicit operator NSNumber(bool value)
{
return new NSNumber(value);
}
}
}

View File

@@ -25,8 +25,8 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Reflection;
namespace Claunia.PropertyList
{
@@ -44,10 +44,10 @@ namespace Claunia.PropertyList
{
/// <summary>
/// The newline character used for generating the XML output.
/// This constant will be different depending on the operating system on
/// which you use this library.
/// To maintain compatibility with the Apple format, only a newline character
/// is used (as opposed to cr+lf which is normally used on Windows).
/// </summary>
readonly internal static string NEWLINE = Environment.NewLine;
readonly internal static string NEWLINE = "\n";
/// <summary>
@@ -100,6 +100,7 @@ namespace Claunia.PropertyList
ToXml(xml, 0);
xml.Append(NSObject.NEWLINE);
xml.Append("</plist>");
xml.Append(NSObject.NEWLINE);
return xml.ToString();
}
@@ -184,7 +185,7 @@ namespace Claunia.PropertyList
NSArray arr = new NSArray(value.Length);
for (int i = 0; i < value.Length; i++)
{
arr.SetValue(i, Wrap(value[i]));
arr.Add(Wrap(value[i]));
}
return arr;
}
@@ -293,7 +294,7 @@ namespace Claunia.PropertyList
bool[] array = (bool[])o;
NSArray nsa = new NSArray(array.Length);
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
nsa.Add(Wrap(array[i]));
return nsa;
}
if (cc.Equals(typeof(float)))
@@ -301,7 +302,7 @@ namespace Claunia.PropertyList
float[] array = (float[])o;
NSArray nsa = new NSArray(array.Length);
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
nsa.Add(Wrap(array[i]));
return nsa;
}
if (cc.Equals(typeof(double)))
@@ -309,7 +310,7 @@ namespace Claunia.PropertyList
double[] array = (double[])o;
NSArray nsa = new NSArray(array.Length);
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
nsa.Add(Wrap(array[i]));
return nsa;
}
if (cc.Equals(typeof(short)))
@@ -317,7 +318,7 @@ namespace Claunia.PropertyList
short[] array = (short[])o;
NSArray nsa = new NSArray(array.Length);
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
nsa.Add(Wrap(array[i]));
return nsa;
}
if (cc.Equals(typeof(int)))
@@ -325,7 +326,7 @@ namespace Claunia.PropertyList
int[] array = (int[])o;
NSArray nsa = new NSArray(array.Length);
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
nsa.Add(Wrap(array[i]));
return nsa;
}
if (cc.Equals(typeof(long)))
@@ -333,7 +334,7 @@ namespace Claunia.PropertyList
long[] array = (long[])o;
NSArray nsa = new NSArray(array.Length);
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
nsa.Add(Wrap(array[i]));
return nsa;
}
return Wrap((Object[])o);
@@ -350,31 +351,8 @@ namespace Claunia.PropertyList
}
if (typeof(List<Object>).IsAssignableFrom(c))
return Wrap(((List<Object>)o).ToArray());
return WrapSerialized(o);
}
/// <summary>
/// Serializes the given object using Java's default object serialization
/// and wraps the serialized object in a NSData object.
/// </summary>
/// <param name="o">The object to serialize and wrap.</param>
/// <returns>A NSData object</returns>
/// <exception cref="SystemException">When the object could not be serialized.</exception>
public static NSData WrapSerialized(Object o)
{
try
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, o);
return new NSData(ms.ToArray());
}
}
catch (IOException)
{
throw new SystemException("The given object of class " + o.GetType() + " could not be serialized and stored in a NSData object.");
}
throw new PropertyListException(string.Format("Cannot wrap an object of type {0}.", o.GetType().Name));
}
/// <summary>
@@ -444,7 +422,7 @@ namespace Claunia.PropertyList
}
if (this is NSString)
{
return ((NSString)this).GetContent();
return ((NSString)this).Content;
}
if (this is NSData)
{

View File

@@ -61,18 +61,10 @@ namespace Claunia.PropertyList
/// Gets this strings content.
/// </summary>
/// <returns>This NSString as .NET string object.</returns>
public string GetContent()
public string Content
{
return content;
}
/// <summary>
/// Sets the contents of this string.
/// </summary>
/// <param name="c">The new content of this string object.</param>
public void SetContent(string c)
{
content = c;
get { return this.content; }
set { this.content = value; }
}
/// <summary>
@@ -81,7 +73,7 @@ namespace Claunia.PropertyList
/// <param name="s">The string to append.</param>
public void Append(NSString s)
{
Append(s.GetContent());
Append(s.Content);
}
/// <summary>
@@ -108,7 +100,7 @@ namespace Claunia.PropertyList
/// <param name="s">The string to prepend.</param>
public void Prepend(NSString s)
{
Prepend(s.GetContent());
Prepend(s.Content);
}
/// <summary>
@@ -163,7 +155,7 @@ namespace Claunia.PropertyList
}
catch (Exception ex)
{
throw new SystemException("Could not encode the NSString into UTF-8: " + ex.Message);
throw new PropertyListException("Could not encode the NSString into UTF-8: " + ex.Message);
}
}
@@ -290,9 +282,9 @@ namespace Claunia.PropertyList
public int CompareTo(Object o)
{
if (o is NSString)
return string.Compare(GetContent(), ((NSString)o).GetContent(), StringComparison.Ordinal);
return string.Compare(Content, ((NSString)o).Content, StringComparison.Ordinal);
if (o is String)
return string.Compare(GetContent(), ((String)o), StringComparison.Ordinal);
return string.Compare(Content, ((String)o), StringComparison.Ordinal);
return -1;
}
@@ -317,6 +309,16 @@ namespace Claunia.PropertyList
return false;
return true;
}
static public explicit operator string(NSString value)
{
return value.content;
}
static public explicit operator NSString(string value)
{
return new NSString(value);
}
}
}

View File

@@ -1,27 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("plist-cil")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Claunia.com")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("© Claunia.com")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.13.0.0")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@@ -0,0 +1,77 @@
// plist-cil - An open source library to parse and generate property lists for .NET
// Copyright (C) 2015 Natalia Portillo
// Copyright (C) 2016 Quamotion
//
// This code is based on:
// plist - An open source library to parse and generate property lists
// Copyright (C) 2014 Daniel Dreibrodt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Runtime.Serialization;
namespace Claunia.PropertyList
{
/// <summary>
/// The exception that is thrown when an property list file could not be processed correctly.
/// </summary>
[Serializable]
public class PropertyListException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="PropertyListException"/> class.
/// </summary>
public PropertyListException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PropertyListException"/> class.
/// </summary>
/// <param name="message">
/// The error message that explains the reason for the exception.
/// </param>
public PropertyListException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PropertyListException"/> class.
/// </summary>
/// <param name="message">
/// The error message that explains the reason for the exception.
/// </param>
/// <param name="inner">
/// The exception that is the cause of the current exception, or <see langword="null"/>
/// if no inner exception is specified.
/// </param>
public PropertyListException(string message, Exception inner)
: base(message, inner)
{
}
#if !NETCORE
protected PropertyListException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}

View File

@@ -32,7 +32,7 @@ namespace Claunia.PropertyList
/// </summary>
/// @author Daniel Dreibrodt
/// @author Natalia Portillo
public class PropertyListFormatException : Exception
public class PropertyListFormatException : PropertyListException
{
/// <summary>
/// Creates a new exception with the given message.

View File

@@ -74,9 +74,17 @@ namespace Claunia.PropertyList
/// <param name="bytes">The type of the property list</param>
static int DetermineType(byte[] bytes)
{
if (bytes.Length == 0)
return TYPE_ERROR_BLANK;
//Skip any possible whitespace at the beginning of the file
int offset = 0;
while (offset < bytes.Length && bytes[offset] == ' ' || bytes[offset] == '\t' || bytes[offset] == '\r' || bytes[offset] == '\n' || bytes[offset] == '\f')
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++;
}
@@ -90,29 +98,42 @@ namespace Claunia.PropertyList
/// <param name="fs">An input stream pointing to the beginning of the property list data.
/// The stream will be reset to the beginning of the property
/// list data after the type has been determined.</param>
static int DetermineType(Stream fs)
static int DetermineType(Stream fs, long offset = 0)
{
//Skip any possible whitespace at the beginning of the file
byte[] magicBytes = new byte[8];
if (fs.Length == 0)
return TYPE_ERROR_BLANK;
long index = offset;
long readLimit = index + 1024;
long mark = readLimit;
fs.Seek(offset, SeekOrigin.Current);
int b;
long mark;
bool bom = false;
//Skip any possible whitespace at the beginning of the file
do
{
mark = fs.Position;
if(++index > readLimit)
{
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))));
}
while(b != -1 && b == ' ' || b == '\t' || b == '\r' || b == '\n' || b == '\f');
while(b != -1 && (b == ' ' || b == '\t' || b == '\r' || b == '\n' || b == '\f' || bom));
if(b==-1)
return TYPE_ERROR_BLANK;
byte[] magicBytes = new byte[8];
magicBytes[0] = (byte)b;
int read = fs.Read(magicBytes, 1, 7);
// Check for UTF-8 BOM prefixed XMLs first.
if (magicBytes[0] == 0xEF && magicBytes[1] == 0xBB && magicBytes[2] == 0xBF && magicBytes[3] == (byte)'<')
return TYPE_XML;
int type = DetermineType(Encoding.ASCII.GetString(magicBytes, 0, read));
fs.Seek(mark, SeekOrigin.Begin);
//if(fs.markSupported())
// fs.reset();
return type;
}
@@ -123,16 +144,11 @@ namespace Claunia.PropertyList
/// <param name="fs">The Stream pointing to the data that should be stored in the array.</param>
internal static byte[] ReadAll(Stream fs)
{
MemoryStream outputStream = new MemoryStream();
byte[] buf = new byte[512];
int read = 512;
while (read == 512)
using (MemoryStream outputStream = new MemoryStream())
{
read = fs.Read(buf, 0, 512);
if (read != -1)
outputStream.Write(buf, 0, read);
fs.CopyTo(outputStream);
return outputStream.ToArray();
}
return outputStream.ToArray();
}
/// <summary>
@@ -152,19 +168,9 @@ namespace Claunia.PropertyList
/// <returns>The root object in the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(FileInfo f)
{
FileStream fis = f.OpenRead();
int type = DetermineType(fis);
fis.Close();
switch (type)
using (FileStream fis = f.OpenRead())
{
case TYPE_BINARY:
return BinaryPropertyListParser.Parse(f);
case TYPE_XML:
return XmlPropertyListParser.Parse(f);
case TYPE_ASCII:
return ASCIIPropertyListParser.Parse(f);
default:
throw new PropertyListFormatException("The given file is not a property list of a supported format.");
return Parse(fis);
}
}
@@ -209,9 +215,13 @@ namespace Claunia.PropertyList
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite);
SaveAsXml(root, fous);
fous.Close();
// 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);
}
}
/// <summary>
@@ -222,9 +232,18 @@ namespace Claunia.PropertyList
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsXml(NSObject root, Stream outStream)
{
#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))
{
w.Write(root.ToXmlPropertyList());
}
#endif
}
/// <summary>
@@ -285,11 +304,11 @@ namespace Claunia.PropertyList
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter w = new StreamWriter(fous, Encoding.ASCII);
w.Write(root.ToASCIIPropertyList());
w.Close();
fous.Close();
using (Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
{
w.Write(root.ToASCIIPropertyList());
}
}
/// <summary>
@@ -303,11 +322,11 @@ namespace Claunia.PropertyList
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter w = new StreamWriter(fous, Encoding.ASCII);
w.Write(root.ToASCIIPropertyList());
w.Close();
fous.Close();
using (Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
{
w.Write(root.ToASCIIPropertyList());
}
}
/// <summary>
@@ -344,11 +363,11 @@ namespace Claunia.PropertyList
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter w = new StreamWriter(fous, Encoding.ASCII);
w.Write(root.ToGnuStepASCIIPropertyList());
w.Close();
fous.Close();
using (Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
{
w.Write(root.ToGnuStepASCIIPropertyList());
}
}
/// <summary>
@@ -362,11 +381,11 @@ namespace Claunia.PropertyList
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter w = new StreamWriter(fous, Encoding.ASCII);
w.Write(root.ToGnuStepASCIIPropertyList());
w.Close();
fous.Close();
using (Stream fous = outFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (StreamWriter w = new StreamWriter(fous, Encoding.ASCII))
{
w.Write(root.ToGnuStepASCIIPropertyList());
}
}
/// <summary>

View File

@@ -23,6 +23,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Linq;
using System.Text;
namespace Claunia.PropertyList
@@ -44,10 +45,130 @@ namespace Claunia.PropertyList
/// <param name="bytes">Bytes.</param>
public UID(String name, byte[] bytes)
{
if(bytes.Length != 1 && bytes.Length != 2 && bytes.Length != 4 && bytes.Length != 8)
throw new ArgumentException("Type argument is not valid.");
this.name = name;
this.bytes = bytes;
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using an unsigned 8-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Unsigned 8-bit number.</param>
public UID(String name, byte number)
{
this.name = name;
this.bytes = new[] { number };
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using a signed 8-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Unsigned 8-bit number.</param>
public UID(String name, sbyte number)
{
this.name = name;
this.bytes = new[] { (byte)number };
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using an unsigned 16-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Unsigned 16-bit number.</param>
public UID(String name, ushort number)
{
this.name = name;
if(number <= byte.MaxValue)
this.bytes = new[] { (byte)number };
else
this.bytes = BitConverter.GetBytes(number).Reverse().ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using a signed 16-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Signed 16-bit number.</param>
public UID(String name, short number)
{
this.name = name;
if(number >= sbyte.MinValue && number <= sbyte.MaxValue)
this.bytes = new[] { (byte)number };
else
this.bytes = BitConverter.GetBytes(number).Reverse().ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using an unsigned 32-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Unsigned 32-bit number.</param>
public UID(String name, uint number)
{
this.name = name;
if(number <= byte.MaxValue)
this.bytes = new[] { (byte)number };
else if(number <= ushort.MaxValue)
this.bytes = BitConverter.GetBytes((ushort)number).Reverse().ToArray();
else
this.bytes = BitConverter.GetBytes(number).Reverse().ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using a signed 32-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Signed 32-bit number.</param>
public UID(String name, int number)
{
this.name = name;
if(number >= sbyte.MinValue && number <= sbyte.MaxValue)
this.bytes = new[] { (byte)number };
if(number >= short.MinValue && number <= short.MaxValue)
this.bytes = BitConverter.GetBytes((short)number).Reverse().ToArray();
else
this.bytes = BitConverter.GetBytes(number).Reverse().ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using an unsigned 64-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Unsigned 64-bit number.</param>
public UID(String name, ulong number)
{
this.name = name;
if(number <= byte.MaxValue)
this.bytes = new[] { (byte)number };
else if(number <= ushort.MaxValue)
this.bytes = BitConverter.GetBytes((ushort)number).Reverse().ToArray();
else if(number <= uint.MaxValue)
this.bytes = BitConverter.GetBytes((uint)number).Reverse().ToArray();
else
this.bytes = BitConverter.GetBytes(number).Reverse().ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="Claunia.PropertyList.UID"/> class using a signed 64-bit number.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="number">Signed 64-bit number.</param>
public UID(String name, long number)
{
this.name = name;
if(number >= sbyte.MinValue && number <= sbyte.MaxValue)
this.bytes = new[] { (byte)number };
if(number >= short.MinValue && number <= short.MaxValue)
this.bytes = BitConverter.GetBytes((short)number).Reverse().ToArray();
if(number >= int.MinValue && number <= int.MaxValue)
this.bytes = BitConverter.GetBytes((int)number).Reverse().ToArray();
else
this.bytes = BitConverter.GetBytes(number).Reverse().ToArray();
}
/// <summary>
/// Gets the bytes.
/// </summary>

View File

@@ -25,6 +25,7 @@
using System.Xml;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Claunia.PropertyList
{
@@ -43,7 +44,14 @@ namespace Claunia.PropertyList
public static NSObject Parse(FileInfo f)
{
XmlDocument doc = new XmlDocument();
doc.Load(f.OpenRead());
var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore };
using (Stream stream = f.OpenRead())
using (XmlReader reader = XmlReader.Create(stream, settings))
{
doc.Load(reader);
}
return ParseDocument(doc);
}
@@ -67,7 +75,14 @@ namespace Claunia.PropertyList
public static NSObject Parse(Stream str)
{
XmlDocument doc = new XmlDocument();
doc.Load(str);
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
using (XmlReader reader = XmlReader.Create(str, settings))
{
doc.Load(reader);
}
return ParseDocument(doc);
}
@@ -79,7 +94,10 @@ namespace Claunia.PropertyList
/// <param name="doc">The XML document.</param>
static NSObject ParseDocument(XmlDocument doc)
{
XmlDocumentType docType = doc.DocumentType;
var docType = doc.ChildNodes
.OfType<XmlNode>()
.SingleOrDefault(n => n.NodeType == XmlNodeType.DocumentType);
if (docType == null)
{
if (!doc.DocumentElement.Name.Equals("plist"))
@@ -140,7 +158,7 @@ namespace Claunia.PropertyList
NSArray array = new NSArray(children.Count);
for (int i = 0; i < children.Count; i++)
{
array.SetValue(i, ParseObject(children[i]));
array.Add(ParseObject(children[i]));
}
return array;
}
@@ -149,9 +167,9 @@ namespace Claunia.PropertyList
if (n.Name.Equals("false"))
return new NSNumber(false);
if (n.Name.Equals("integer"))
return new NSNumber(GetNodeTextContents(n));
return new NSNumber(GetNodeTextContents(n), NSNumber.INTEGER);
if (n.Name.Equals("real"))
return new NSNumber(GetNodeTextContents(n));
return new NSNumber(GetNodeTextContents(n), NSNumber.REAL);
if (n.Name.Equals("string"))
return new NSString(GetNodeTextContents(n));
if (n.Name.Equals("data"))

View File

@@ -1,137 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5EA40CD5-CB98-4FD5-8628-3B399EACB38B}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Claunia.PropertyList</RootNamespace>
<AssemblyName>plist-cil</AssemblyName>
<ReleaseVersion>1.13</ReleaseVersion>
<TargetFrameworks>netcoreapp1.0;netstandard1.3;netstandard1.4;netstandard1.6;net40;net45</TargetFrameworks>
<Version>1.16</Version>
<Authors>Natalia Portillo</Authors>
<Company>Claunia.com</Company>
<Description>MIT licensed C#/.NET parser and writer for Apple and GnuStep Property Lists, supporting ASCII, Binary and Xml formats, based on Java's dd-plist.</Description>
<Copyright>© 2015-2017 Natalia Portillo</Copyright>
<PackageLicenseUrl>https://raw.githubusercontent.com/claunia/plist-cil/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>http://www.github.com/claunia/plist-cil</PackageProjectUrl>
<RepositoryUrl>http://www.github.com/claunia/plist-cil</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>apple propertylist property list gnustep plist</PackageTags>
<PackageReleaseNotes>Added support for .NETStandard1.4.
Enhanced binary compatibility with Apple.
Correct opening of plists with unescaped UTF8 strings.
Added support for parsing hex numbers.
Added explicit casts for NSNumber, NSData, NSDate and NSString.
Added examples to README.</PackageReleaseNotes>
<NeutralLanguage>en-US</NeutralLanguage>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>plist-cil.snk</AssemblyOriginatorKeyFile>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;RELEASE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<DocumentationFile>bin\Release\plist-cil.xml</DocumentationFile>
<CustomCommands>
<CustomCommands>
<Command type="AfterBuild" command="monodocer -pretty -importslashdoc:plist-cil.xml -assembly:plist-cil.dll -path:docs/mono" workingdir="${TargetDir}" />
<Command type="AfterBuild" command="mdoc export-html -o docs/html docs/mono" workingdir="${TargetDir}" />
<Command type="AfterBuild" command="zip -9r ${ProjectName}.zip ." workingdir="${TargetDir}" />
</CustomCommands>
</CustomCommands>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp1.0' Or '$(TargetFramework)' == 'netstandard1.3' Or '$(TargetFramework)' == 'netstandard1.4' Or '$(TargetFramework)' == 'netstandard1.6'">
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp1.0|AnyCPU'">
<DocumentationFile>bin\Release\netcoreapp1.0\plist-cil.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net40|AnyCPU'">
<DocumentationFile>bin\Release\net40\plist-cil.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net40' Or '$(TargetFramework)' == 'net45'">
<Reference Include="System" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="NSObject.cs" />
<Compile Include="NSNumber.cs" />
<Compile Include="NSString.cs" />
<Compile Include="NSSet.cs" />
<Compile Include="UID.cs" />
<Compile Include="NSDate.cs" />
<Compile Include="NSArray.cs" />
<Compile Include="NSData.cs" />
<Compile Include="NSDictionary.cs" />
<Compile Include="PropertyListFormatException.cs" />
<Compile Include="PropertyListParser.cs" />
<Compile Include="ASCIIPropertyListParser.cs" />
<Compile Include="BinaryPropertyListParser.cs" />
<Compile Include="BinaryPropertyListWriter.cs" />
<Compile Include="XmlPropertyListParser.cs" />
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp1.0' Or '$(TargetFramework)' == 'netstandard1.3' Or '$(TargetFramework)' == 'netstandard1.4' Or '$(TargetFramework)' == 'netstandard1.6'">
<PackageReference Include="System.Diagnostics.Debug" Version="4.3.0" />
<PackageReference Include="System.Linq" Version="4.3.0" />
<PackageReference Include="System.Globalization" Version="4.3.0" />
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="System.Resources.ResourceManager" Version="4.3.0" />
<PackageReference Include="System.Reflection" Version="4.3.0" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.3.0" />
<PackageReference Include="System.Runtime.Extensions" Version="4.3.0" />
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
<PackageReference Include="System.Runtime.Numerics" Version="4.3.0" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<MonoDevelop>
<Properties>
<Policies>
<NameConventionPolicy>
<Rules>
<NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredPrefixes>
<String>I</String>
</RequiredPrefixes>
</NamingRule>
<NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredSuffixes>
<String>Attribute</String>
</RequiredSuffixes>
</NamingRule>
<NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredSuffixes>
<String>EventArgs</String>
</RequiredSuffixes>
</NamingRule>
<NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredSuffixes>
<String>Exception</String>
</RequiredSuffixes>
</NamingRule>
<NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="PascalCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
<NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Protected, Public" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
<NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
<AllowedPrefixes>
<String>_</String>
<String>m_</String>
</AllowedPrefixes>
</NamingRule>
<NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
<NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
<AllowedPrefixes>
<String>_</String>
<String>m_</String>
</AllowedPrefixes>
</NamingRule>
<NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Parameters" AffectedEntity="Parameter" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredPrefixes>
<String>T</String>
</RequiredPrefixes>
</NamingRule>
</Rules>
</NameConventionPolicy>
</Policies>
</Properties>
</MonoDevelop>
</ProjectExtensions>
<ItemGroup>
<None Include="..\LICENSE">
<Link>LICENSE</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Gettext-ScanForTranslations>False</Gettext-ScanForTranslations>
</None>
<None Include="..\README.md">
<Link>README.md</Link>
<Link>README.txt</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Gettext-ScanForTranslations>False</Gettext-ScanForTranslations>
</None>
<None Include="ChangeLog">
<Gettext-ScanForTranslations>False</Gettext-ScanForTranslations>
<Link>ChangeLog.txt</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
<id>plist-cil</id>
<version>1.16</version>
<title>plist-cil</title>
<authors>Natalia Portillo</authors>
<owners>Natalia Portillo</owners>
<licenseUrl>https://raw.githubusercontent.com/claunia/plist-cil/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/claunia/plist-cil</projectUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>MIT licensed C#/.NET parser and writer for Apple and GnuStep Property Lists, supporting ASCII, Binary and Xml formats, based on Java's dd-plist.</description>
<summary>MIT licensed C#/.NET parser and writer for Apple and GnuStep Property Lists, supporting ASCII, Binary and Xml formats.</summary>
<releaseNotes>
Added support for .NETStandard1.4.
Enhanced binary compatibility with Apple.
Correct opening of plists with unescaped UTF8 strings.
Added support for parsing hex numbers.
Added explicit casts for NSNumber, NSData, NSDate and NSString.
Added examples to README.
</releaseNotes>
<copyright>Copyright (C) 2015-2017 Natalia Portillo</copyright>
<tags>plist apple propertylist property list gnustep</tags>
</metadata>
<files>
<file src="bin/Release/*.dll" target="lib"/>
<file src="bin/Release/ChangeLog" target="content\docs\ChangeLog.txt"/>
<file src="bin/Release/LICENSE" target="content\docs\LICENSE.txt"/>
<file src="bin/Release/*.xml" target="lib"/>
<file src="bin/Release/README.md" target="content\docs\README.md"/>
<file src="bin/Release/docs/**/*.*" target="content\docs"/>
</files>
</package>

BIN
plist-cil/plist-cil.snk Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
// !$*UTF8*$!
{
path = "JÔÖú@2x.jpg";
"Key QÔÖª@2x \u4321" = "QÔÖú@2x 啕.jpg";
}