mirror of
https://github.com/claunia/plist-cil.git
synced 2025-12-16 19:14:26 +00:00
Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9977e92d3 | |||
| 302bfca681 | |||
| 01b62a907c | |||
| df68433456 | |||
| 96b66d2516 | |||
| 5a74d9f9ee | |||
| 2b0488f94a | |||
| fce5f88895 | |||
| 9a10128482 | |||
| 67b73b4319 | |||
| 114fd9b2fc | |||
| 673825548f | |||
| 25e2063112 | |||
| 1979dab8fa | |||
| c8d3e26a84 | |||
| a2ace4f4d8 | |||
| 4af6672d37 | |||
|
|
65f12a2607 | ||
|
|
d9670db803 | ||
| 50335a9bba | |||
| f56f0606f1 | |||
| 65a932dfd7 | |||
| b2a1f093b0 | |||
|
|
7982cad715 | ||
|
|
4f31fc611f | ||
|
|
e0d0baa985 | ||
|
|
bed10a35ca | ||
|
|
1399b4ba2a | ||
|
|
e20798c746 | ||
|
|
fb29bb8131 | ||
|
|
b07e637c6d | ||
|
|
b4974acba9 | ||
|
|
8dc5f8ba24 | ||
|
|
6c95260157 | ||
|
|
275f7fdd8f | ||
| e071148e2b | |||
| c646d1beb2 | |||
|
|
fb7e431ac8 | ||
| 64dc55d047 | |||
| 036227e346 | |||
|
|
03c95ce192 | ||
|
|
c2f15567c7 | ||
|
|
dfee77b724 | ||
|
|
1ff1bcde3b | ||
| 2148034a71 | |||
| 10e92e31db | |||
| 18e9e294e2 | |||
| b9aa325825 | |||
|
|
bf031fadab | ||
|
|
66ac10e4be | ||
|
|
12418b7284 | ||
|
|
3c4e3257f2 | ||
|
|
e432c71e26 | ||
| 6571783fab | |||
|
|
a58ff42cef | ||
|
|
5d16fb0275 | ||
|
|
55c515bd39 | ||
|
|
ec6d00342f | ||
|
|
22737bb9d2 | ||
|
|
8f04882f98 | ||
|
|
bdf4351d1d | ||
|
|
844d9f3b12 | ||
|
|
cbfb5c8290 | ||
|
|
f284d2abd0 | ||
|
|
0a7483ff75 | ||
| accdc880ae | |||
|
|
2bacfb7037 | ||
|
|
df27f9d5ac | ||
| ccfba8ebc1 | |||
|
|
5a1a9d18d7 | ||
|
|
156a55c84a | ||
|
|
6f03f99db4 | ||
|
|
1d3f49824c | ||
|
|
438c75173b | ||
| 7ceae0ddc3 | |||
| cf2b51e41d | |||
| a469709814 | |||
| d17e1f56a0 | |||
| fbd57a18be | |||
| df673df0a9 | |||
| 399a043c62 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -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
15
.travis.yml
Normal 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
|
||||
24
ChangeLog
24
ChangeLog
@@ -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
155
README.md
@@ -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.
|
||||
[](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"));
|
||||
12
SvnInfo.txt
12
SvnInfo.txt
@@ -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
15
appveyor.yml
Normal 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"
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
95
plist-cil.test/NSArrayTests.cs
Normal file
95
plist-cil.test/NSArrayTests.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
31
plist-cil.test/NSDateTests.cs
Normal file
31
plist-cil.test/NSDateTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
76
plist-cil.test/NSNumberTests.cs
Normal file
76
plist-cil.test/NSNumberTests.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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("")]
|
||||
|
||||
23
plist-cil.test/PropertyListParserTests.cs
Normal file
23
plist-cil.test/PropertyListParserTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
plist-cil.test/UseCultureAttribute.cs
Normal file
96
plist-cil.test/UseCultureAttribute.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
8
plist-cil.test/test-files/ResourceRules.plist
Normal file
8
plist-cil.test/test-files/ResourceRules.plist
Normal 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>
|
||||
80
plist-cil.test/test-files/Roundtrip.plist
Normal file
80
plist-cil.test/test-files/Roundtrip.plist
Normal 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>
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
139
plist-cil/NSArray.IList.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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("")]
|
||||
|
||||
77
plist-cil/PropertyListException.cs
Normal file
77
plist-cil/PropertyListException.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
121
plist-cil/UID.cs
121
plist-cil/UID.cs
@@ -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>
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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>
|
||||
|
||||
33
plist-cil/plist-cil.nuspec
Normal file
33
plist-cil/plist-cil.nuspec
Normal 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
BIN
plist-cil/plist-cil.snk
Normal file
Binary file not shown.
5
test-files/test-ascii-utf8.plist
Normal file
5
test-files/test-ascii-utf8.plist
Normal file
@@ -0,0 +1,5 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
path = "JÔÖú@2x.jpg";
|
||||
"Key QÔÖª@2x \u4321" = "QÔÖú@2x 啕.jpg";
|
||||
}
|
||||
Reference in New Issue
Block a user