Reformat code.

This commit is contained in:
2015-02-20 00:00:26 +00:00
parent 46a0c3ddf3
commit 49afbe3bdc
16 changed files with 1343 additions and 668 deletions

View File

@@ -61,7 +61,8 @@ namespace Claunia.PropertyList
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
/// <exception cref="IOException">When an error occured while reading from the input stream.</exception>
public static NSObject Parse(FileInfo f) {
public static NSObject Parse(FileInfo f)
{
return Parse(f.OpenRead());
}
@@ -72,7 +73,8 @@ namespace Claunia.PropertyList
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
/// <exception cref="IOException"></exception>
public static NSObject Parse(Stream fs) {
public static NSObject Parse(Stream fs)
{
byte[] buf = PropertyListParser.ReadAll(fs);
fs.Close();
return Parse(buf);
@@ -84,7 +86,8 @@ namespace Claunia.PropertyList
/// <param name="bytes">The ASCII property list data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
/// <exception cref="FormatException">When an error occurs during parsing.</exception>
public static NSObject Parse(byte[] bytes) {
public static NSObject Parse(byte[] bytes)
{
ASCIIPropertyListParser parser = new ASCIIPropertyListParser(bytes);
return parser.Parse();
}
@@ -141,7 +144,8 @@ namespace Claunia.PropertyList
/**
* Only allow subclasses to change instantiation.
*/
protected ASCIIPropertyListParser() {
protected ASCIIPropertyListParser()
{
}
@@ -149,7 +153,8 @@ 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>
private ASCIIPropertyListParser(byte[] propertyListContent) {
private ASCIIPropertyListParser(byte[] propertyListContent)
{
data = propertyListContent;
}
@@ -158,8 +163,10 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>Whether the given tokens occur at the current parsing position.</returns>
/// <param name="sequence">The sequence of tokens to look for.</param>
private bool AcceptSequence(params char[] sequence) {
for (int i = 0; i < sequence.Length; i++) {
private bool AcceptSequence(params char[] sequence)
{
for (int i = 0; i < sequence.Length; i++)
{
if (data[index + i] != sequence[i])
return false;
}
@@ -172,9 +179,11 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="acceptableSymbols">The symbols to check.</param>
/// <returns>Whether one of the symbols can be accepted or not.</returns>
private bool Accept(params char[] acceptableSymbols) {
private bool Accept(params char[] acceptableSymbols)
{
bool symbolPresent = false;
foreach (char c in acceptableSymbols) {
foreach (char c in acceptableSymbols)
{
if (data[index] == c)
symbolPresent = true;
}
@@ -187,7 +196,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="acceptableSymbol">The symbol to check.</param>
/// <returns>Whether the symbol can be accepted or not.</returns>
private bool Accept(char acceptableSymbol) {
private bool Accept(char acceptableSymbol)
{
return data[index] == acceptableSymbol;
}
@@ -196,13 +206,16 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="expectedSymbols">The expected symbols.</param>
/// <exception cref="FormatException">If none of the expected symbols could be found.</exception>
private void Expect(params char[] expectedSymbols) {
if (!Accept(expectedSymbols)) {
private void Expect(params char[] expectedSymbols)
{
if (!Accept(expectedSymbols))
{
String excString = "Expected '" + expectedSymbols[0] + "'";
for (int i = 1; i < expectedSymbols.Length; i++) {
for (int i = 1; i < expectedSymbols.Length; i++)
{
excString += " or '" + expectedSymbols[i] + "'";
}
excString += " but found '" + (char) data[index] + "'";
excString += " but found '" + (char)data[index] + "'";
throw new FormatException(String.Format("{0} at {1}", excString, index));
}
}
@@ -212,7 +225,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="expectedSymbol">The expected symbol.</param>
/// <exception cref="FormatException">If the expected symbol could be found.</exception>
private void Expect(char expectedSymbol) {
private void Expect(char expectedSymbol)
{
if (!Accept(expectedSymbol))
throw new FormatException(String.Format("Expected '{0}' but found '{1}' at {2}", expectedSymbol, data[index], index));
}
@@ -222,7 +236,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="symbol">The symbol to read.</param>
/// <exception cref="FormatException">If the expected symbol could not be read.</exception>
private void Read(char symbol) {
private void Read(char symbol)
{
Expect(symbol);
index++;
}
@@ -230,7 +245,8 @@ namespace Claunia.PropertyList
/**
* Skips the current symbol.
*/
private void Skip() {
private void Skip()
{
index++;
}
@@ -238,34 +254,42 @@ namespace Claunia.PropertyList
/// Skips several symbols
/// </summary>
/// <param name="numSymbols">The amount of symbols to skip.</param>
private void Skip(int numSymbols) {
private void Skip(int numSymbols)
{
index += numSymbols;
}
/**
* Skips all whitespaces and comments from the current parsing position onward.
*/
private void SkipWhitespacesAndComments() {
private void SkipWhitespacesAndComments()
{
bool commentSkipped;
do {
do
{
commentSkipped = false;
//Skip whitespaces
while (Accept(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE, WHITESPACE_SPACE, WHITESPACE_TAB)) {
while (Accept(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE, WHITESPACE_SPACE, WHITESPACE_TAB))
{
Skip();
}
//Skip single line comments "//..."
if (AcceptSequence(COMMENT_BEGIN_TOKEN, SINGLELINE_COMMENT_SECOND_TOKEN)) {
if (AcceptSequence(COMMENT_BEGIN_TOKEN, SINGLELINE_COMMENT_SECOND_TOKEN))
{
Skip(2);
ReadInputUntil(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE);
commentSkipped = true;
}
//Skip multi line comments "/* ... */"
else if (AcceptSequence(COMMENT_BEGIN_TOKEN, MULTILINE_COMMENT_SECOND_TOKEN)) {
else if (AcceptSequence(COMMENT_BEGIN_TOKEN, MULTILINE_COMMENT_SECOND_TOKEN))
{
Skip(2);
while (true) {
if (AcceptSequence(MULTILINE_COMMENT_SECOND_TOKEN, MULTILINE_COMMENT_END_TOKEN)) {
while (true)
{
if (AcceptSequence(MULTILINE_COMMENT_SECOND_TOKEN, MULTILINE_COMMENT_END_TOKEN))
{
Skip(2);
break;
}
@@ -282,10 +306,12 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The input until one the given symbols.</returns>
/// <param name="symbols">The symbols that can occur after the string to read.</param>
private string ReadInputUntil(params char[] symbols) {
private string ReadInputUntil(params char[] symbols)
{
string s = "";
while (!Accept(symbols)) {
s += (char) data[index];
while (!Accept(symbols))
{
s += (char)data[index];
Skip();
}
return s;
@@ -296,10 +322,12 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The input until the given symbol.</returns>
/// <param name="symbol">The symbol that can occur after the string to read.</param>
private string ReadInputUntil(char symbol) {
private string ReadInputUntil(char symbol)
{
String s = "";
while (!Accept(symbol)) {
s += (char) data[index];
while (!Accept(symbol))
{
s += (char)data[index];
Skip();
}
return s;
@@ -311,13 +339,17 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The root object of the property list. This can either be a NSDictionary or a NSArray.</returns>
/// <exception cref="FormatException">When an error occured during parsing</exception>
public NSObject Parse() {
public NSObject Parse()
{
index = 0;
SkipWhitespacesAndComments();
Expect(DICTIONARY_BEGIN_TOKEN, ARRAY_BEGIN_TOKEN, COMMENT_BEGIN_TOKEN);
try {
try
{
return ParseObject();
} catch (IndexOutOfRangeException ex) {
}
catch (IndexOutOfRangeException ex)
{
throw new FormatException(String.Format("Reached end of input unexpectedly at {0}.", index));
}
}
@@ -328,37 +360,53 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The parsed NSObject.</returns>
/// <seealso cref="ASCIIPropertyListParser.index"/>
private NSObject ParseObject() {
switch (data[index]) {
case (byte)ARRAY_BEGIN_TOKEN: {
private NSObject ParseObject()
{
switch (data[index])
{
case (byte)ARRAY_BEGIN_TOKEN:
{
return ParseArray();
}
case (byte)DICTIONARY_BEGIN_TOKEN: {
case (byte)DICTIONARY_BEGIN_TOKEN:
{
return ParseDictionary();
}
case (byte)DATA_BEGIN_TOKEN: {
case (byte)DATA_BEGIN_TOKEN:
{
return ParseData();
}
case (byte)QUOTEDSTRING_BEGIN_TOKEN: {
case (byte)QUOTEDSTRING_BEGIN_TOKEN:
{
string quotedString = ParseQuotedString();
//apple dates are quoted strings of length 20 and after the 4 year digits a dash is found
if (quotedString.Length == 20 && quotedString[4] == DATE_DATE_FIELD_DELIMITER) {
try {
if (quotedString.Length == 20 && quotedString[4] == DATE_DATE_FIELD_DELIMITER)
{
try
{
return new NSDate(quotedString);
} catch (Exception ex) {
}
catch (Exception ex)
{
//not a date? --> return string
return new NSString(quotedString);
}
} else {
}
else
{
return new NSString(quotedString);
}
}
default: {
default:
{
//0-9
if (data[index] > 0x2F && data[index] < 0x3A) {
if (data[index] > 0x2F && data[index] < 0x3A)
{
//could be a date or just a string
return ParseDateString();
} else {
}
else
{
//non-numerical -> string or boolean
string parsedString = ParseString();
return new NSString(parsedString);
@@ -372,17 +420,22 @@ namespace Claunia.PropertyList
/// The prerequisite for calling this method is, that an array begin token has been read.
/// </summary>
/// <returns>The array found at the parsing position.</returns>
private NSArray ParseArray() {
private NSArray ParseArray()
{
//Skip begin token
Skip();
SkipWhitespacesAndComments();
List<NSObject> objects = new List<NSObject>();
while (!Accept(ARRAY_END_TOKEN)) {
while (!Accept(ARRAY_END_TOKEN))
{
objects.Add(ParseObject());
SkipWhitespacesAndComments();
if (Accept(ARRAY_ITEM_DELIMITER_TOKEN)) {
if (Accept(ARRAY_ITEM_DELIMITER_TOKEN))
{
Skip();
} else {
}
else
{
break; //must have reached end of array
}
SkipWhitespacesAndComments();
@@ -397,17 +450,22 @@ namespace Claunia.PropertyList
/// The prerequisite for calling this method is, that a dictionary begin token has been read.
/// </summary>
/// <returns>The dictionary found at the parsing position.</returns>
private NSDictionary ParseDictionary() {
private NSDictionary ParseDictionary()
{
//Skip begin token
Skip();
SkipWhitespacesAndComments();
NSDictionary dict = new NSDictionary();
while (!Accept(DICTIONARY_END_TOKEN)) {
while (!Accept(DICTIONARY_END_TOKEN))
{
//Parse key
string keyString;
if (Accept(QUOTEDSTRING_BEGIN_TOKEN)) {
if (Accept(QUOTEDSTRING_BEGIN_TOKEN))
{
keyString = ParseQuotedString();
} else {
}
else
{
keyString = ParseString();
}
SkipWhitespacesAndComments();
@@ -433,30 +491,40 @@ namespace Claunia.PropertyList
/// The prerequisite for calling this method is, that a data begin token has been read.
/// </summary>
/// <returns>The data object found at the parsing position.</returns>
private NSObject ParseData() {
private NSObject ParseData()
{
NSObject obj = null;
//Skip begin token
Skip();
if (Accept(DATA_GSOBJECT_BEGIN_TOKEN)) {
if (Accept(DATA_GSOBJECT_BEGIN_TOKEN))
{
Skip();
Expect(DATA_GSBOOL_BEGIN_TOKEN, DATA_GSDATE_BEGIN_TOKEN, DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN);
if (Accept(DATA_GSBOOL_BEGIN_TOKEN)) {
if (Accept(DATA_GSBOOL_BEGIN_TOKEN))
{
//Boolean
Skip();
Expect(DATA_GSBOOL_TRUE_TOKEN, DATA_GSBOOL_FALSE_TOKEN);
if (Accept(DATA_GSBOOL_TRUE_TOKEN)) {
if (Accept(DATA_GSBOOL_TRUE_TOKEN))
{
obj = new NSNumber(true);
} else {
}
else
{
obj = new NSNumber(false);
}
//Skip the parsed boolean token
Skip();
} else if (Accept(DATA_GSDATE_BEGIN_TOKEN)) {
}
else if (Accept(DATA_GSDATE_BEGIN_TOKEN))
{
//Date
Skip();
string dateString = ReadInputUntil(DATA_END_TOKEN);
obj = new NSDate(dateString);
} else if (Accept(DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN)) {
}
else if (Accept(DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN))
{
//Number
Skip();
string numberString = ReadInputUntil(DATA_END_TOKEN);
@@ -464,16 +532,19 @@ namespace Claunia.PropertyList
}
//parse data end token
Read(DATA_END_TOKEN);
} else {
}
else
{
string dataString = ReadInputUntil(DATA_END_TOKEN);
dataString = Regex.Replace(dataString, "\\s+", "");
int numBytes = dataString.Length / 2;
byte[] bytes = new byte[numBytes];
for (int i = 0; i < bytes.Length; i++) {
for (int i = 0; i < bytes.Length; i++)
{
string byteString = dataString.Substring(i * 2, 2);
int byteValue = Convert.ToInt32(byteString, 16);
bytes[i] = (byte) byteValue;
bytes[i] = (byte)byteValue;
}
obj = new NSData(bytes);
@@ -488,12 +559,17 @@ namespace Claunia.PropertyList
/// Attempts to parse a plain string as a date if possible.
/// </summary>
/// <returns>A NSDate if the string represents such an object. Otherwise a NSString is returned.</returns>
private NSObject ParseDateString() {
private NSObject ParseDateString()
{
string numericalString = ParseString();
if (numericalString.Length > 4 && numericalString[4] == DATE_DATE_FIELD_DELIMITER) {
try {
if (numericalString.Length > 4 && numericalString[4] == DATE_DATE_FIELD_DELIMITER)
{
try
{
return new NSDate(numericalString);
} catch(Exception ex) {
}
catch (Exception ex)
{
//An exception occurs if the string is not a date but just a string
}
}
@@ -505,7 +581,8 @@ namespace Claunia.PropertyList
/// The string is made up of all characters to the next whitespace, delimiter token or assignment token.
/// </summary>
/// <returns>The string found at the current parsing position.</returns>
private string ParseString() {
private string ParseString()
{
return ReadInputUntil(WHITESPACE_SPACE, WHITESPACE_TAB, WHITESPACE_NEWLINE, WHITESPACE_CARRIAGE_RETURN,
ARRAY_ITEM_DELIMITER_TOKEN, DICTIONARY_ITEM_DELIMITER_TOKEN, DICTIONARY_ASSIGN_TOKEN, ARRAY_END_TOKEN);
}
@@ -516,23 +593,29 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The quoted string found at the parsing method with all special characters unescaped.</returns>
/// <exception cref="FormatException">If an error occured during parsing.</exception>
private string ParseQuotedString() {
private string ParseQuotedString()
{
//Skip begin token
Skip();
string quotedString = "";
bool unescapedBackslash = true;
//Read from opening quotation marks to closing quotation marks and skip escaped quotation marks
while (data[index] != QUOTEDSTRING_END_TOKEN || (data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash)) {
quotedString += (char) data[index];
if (Accept(QUOTEDSTRING_ESCAPE_TOKEN)) {
while (data[index] != QUOTEDSTRING_END_TOKEN || (data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash))
{
quotedString += (char)data[index];
if (Accept(QUOTEDSTRING_ESCAPE_TOKEN))
{
unescapedBackslash = !(data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash);
}
Skip();
}
string unescapedString;
try {
try
{
unescapedString = ParseQuotedString(quotedString);
} catch (Exception ex) {
}
catch (Exception ex)
{
throw new FormatException(String.Format("The quoted string could not be parsed at {0}.", index));
}
//skip end token
@@ -554,28 +637,34 @@ namespace Claunia.PropertyList
/// <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) {
public static string ParseQuotedString(string s)
{
List<byte> strBytes = new List<byte>();
CharEnumerator c = s.GetEnumerator();
while(c.MoveNext()) {
switch (c.Current) {
case '\\': { //An escaped sequence is following
while (c.MoveNext())
{
switch (c.Current)
{
case '\\':
{ //An escaped sequence is following
byte[] bts = Encoding.UTF8.GetBytes(ParseEscapedSequence(c));
foreach (byte b in bts)
strBytes.Add(b);
break;
}
default: { //a normal ASCII char
strBytes.Add((byte) 0);
strBytes.Add((byte) c.Current);
default:
{ //a normal ASCII char
strBytes.Add((byte)0);
strBytes.Add((byte)c.Current);
break;
}
}
}
byte[] bytArr = new byte[strBytes.Count];
int i = 0;
foreach (byte b in strBytes) {
foreach (byte b in strBytes)
{
bytArr[i] = b;
i++;
}
@@ -585,7 +674,8 @@ namespace Claunia.PropertyList
//If the string can be represented in the ASCII codepage
// --> use ASCII encoding
try{
try
{
if (asciiEncoder == null)
asciiEncoder = Encoding.GetEncoding("ascii", EncoderExceptionFallback.ExceptionFallback, DecoderExceptionFallback.ExceptionFallback);
return asciiEncoder.GetString(Encoding.Convert(Encoding.BigEndianUnicode, asciiEncoder, bytArr));
@@ -604,22 +694,36 @@ 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(CharEnumerator iterator)
{
iterator.MoveNext();
char c = iterator.Current;
if (c == '\\') {
return Encoding.UTF8.GetString(new byte[]{0, (byte)'\\'});
} else if (c == '"') {
return Encoding.UTF8.GetString(new byte[]{0, (byte)'\"'});
} else if (c == 'b') {
return Encoding.UTF8.GetString(new byte[]{0, (byte)'\b'});
} else if (c == 'n') {
return Encoding.UTF8.GetString(new byte[]{0, (byte)'\n'});
} else if (c == 'r') {
return Encoding.UTF8.GetString(new byte[]{0, (byte)'\r'});
} else if (c == 't') {
return Encoding.UTF8.GetString(new byte[]{0, (byte)'\t'});
} else if (c == 'U' || c == 'u') {
if (c == '\\')
{
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\\' });
}
else if (c == '"')
{
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\"' });
}
else if (c == 'b')
{
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\b' });
}
else if (c == 'n')
{
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\n' });
}
else if (c == 'r')
{
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\r' });
}
else if (c == 't')
{
return Encoding.UTF8.GetString(new byte[]{ 0, (byte)'\t' });
}
else if (c == 'U' || c == 'u')
{
//4 digit hex Unicode value
string byte1 = "";
iterator.MoveNext();
@@ -631,9 +735,11 @@ namespace Claunia.PropertyList
byte2 += iterator.Current;
iterator.MoveNext();
byte2 += iterator.Current;
byte[] stringBytes = {(byte) Convert.ToInt32(byte1, 16), (byte) Convert.ToInt32(byte2, 16)};
byte[] stringBytes = { (byte)Convert.ToInt32(byte1, 16), (byte)Convert.ToInt32(byte2, 16) };
return Encoding.UTF8.GetString(stringBytes);
} else {
}
else
{
//3 digit octal ASCII value
string num = "";
num += c;
@@ -642,7 +748,7 @@ namespace Claunia.PropertyList
iterator.MoveNext();
num += iterator.Current;
int asciiCode = Convert.ToInt32(num, 8);
byte[] stringBytes = {0, (byte) asciiCode};
byte[] stringBytes = { 0, (byte)asciiCode };
return Encoding.UTF8.GetString(stringBytes);
}
}

View File

@@ -87,7 +87,8 @@ namespace Claunia.PropertyList
/// <param name="data">The binary property list's data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
public static NSObject Parse(byte[] data) {
public static NSObject Parse(byte[] data)
{
BinaryPropertyListParser parser = new BinaryPropertyListParser();
return parser.DoParse(data);
}
@@ -98,10 +99,12 @@ namespace Claunia.PropertyList
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
/// <param name="data">The binary property list's data.</param>
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
private NSObject DoParse(byte[] data) {
private NSObject DoParse(byte[] data)
{
bytes = data;
string magic = Encoding.ASCII.GetString(CopyOfRange(bytes, 0, 8));
if (!magic.StartsWith("bplist")) {
if (!magic.StartsWith("bplist"))
{
throw new PropertyListFormatException("The given data is no binary property list. Wrong magic bytes: " + magic);
}
@@ -114,9 +117,10 @@ namespace Claunia.PropertyList
// 1.5 - Lion
// 2.0 - Snow Lion
if (majorVersion > 0) {
if (majorVersion > 0)
{
throw new PropertyListFormatException("Unsupported binary property list format: v" + majorVersion + "." + minorVersion + ". " +
"Version 1.0 and later are not yet supported.");
"Version 1.0 and later are not yet supported.");
}
/*
@@ -124,15 +128,15 @@ 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);
offsetSize = (int)ParseUnsignedInt(trailer, 6, 7);
//System.Console.WriteLine("offsetSize: "+offsetSize);
objectRefSize = (int) ParseUnsignedInt(trailer, 7, 8);
objectRefSize = (int)ParseUnsignedInt(trailer, 7, 8);
//System.Console.WriteLine("objectRefSize: "+objectRefSize);
numObjects = (int) ParseUnsignedInt(trailer, 8, 16);
numObjects = (int)ParseUnsignedInt(trailer, 8, 16);
//System.Console.WriteLine("numObjects: "+numObjects);
topObject = (int) ParseUnsignedInt(trailer, 16, 24);
topObject = (int)ParseUnsignedInt(trailer, 16, 24);
//System.Console.WriteLine("topObject: "+topObject);
offsetTableOffset = (int) ParseUnsignedInt(trailer, 24, 32);
offsetTableOffset = (int)ParseUnsignedInt(trailer, 24, 32);
//System.Console.WriteLine("offsetTableOffset: "+offsetTableOffset);
/*
@@ -140,9 +144,10 @@ namespace Claunia.PropertyList
*/
offsetTable = new int[numObjects];
for (int i = 0; i < numObjects; i++) {
for (int i = 0; i < numObjects; i++)
{
byte[] offsetBytes = CopyOfRange(bytes, offsetTableOffset + i * offsetSize, offsetTableOffset + (i + 1) * offsetSize);
offsetTable[i] = (int) ParseUnsignedInt(offsetBytes);
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("]");*/
@@ -157,7 +162,8 @@ namespace Claunia.PropertyList
/// <param name="fs">The input stream that points to the property list's data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
public static NSObject Parse(Stream fs) {
public static NSObject Parse(Stream fs)
{
//Read all bytes into a list
byte[] buf = PropertyListParser.ReadAll(fs);
fs.Close();
@@ -170,7 +176,8 @@ namespace Claunia.PropertyList
/// <param name="f">The binary property list file</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
public static NSObject Parse(FileInfo f) {
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.
@@ -192,67 +199,83 @@ namespace Claunia.PropertyList
/// <returns>The parsed object.</returns>
/// <param name="obj">The object ID.</param>
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
private NSObject ParseObject(int obj) {
private NSObject ParseObject(int obj)
{
int offset = offsetTable[obj];
byte type = bytes[offset];
int objType = (type & 0xF0) >> 4; //First 4 bits
int objInfo = (type & 0x0F); //Second 4 bits
switch (objType) {
case 0x0: {
switch (objType)
{
case 0x0:
{
//Simple
switch (objInfo) {
case 0x0: {
switch (objInfo)
{
case 0x0:
{
//null object (v1.0 and later)
return null;
}
case 0x8: {
case 0x8:
{
//false
return new NSNumber(false);
}
case 0x9: {
case 0x9:
{
//true
return new NSNumber(true);
}
case 0xC: {
case 0xC:
{
//URL with no base URL (v1.0 and later)
//TODO
break;
}
case 0xD: {
case 0xD:
{
//URL with base URL (v1.0 and later)
//TODO
break;
}
case 0xE: {
case 0xE:
{
//16-byte UUID (v1.0 and later)
//TODO
break;
}
case 0xF: {
case 0xF:
{
//filler byte
return null;
}
}
break;
}
case 0x1: {
case 0x1:
{
//integer
int length = (int) Math.Pow(2, objInfo);
return new NSNumber(CopyOfRange(bytes, offset + 1, offset + 1 + length), NSNumber.INTEGER);
int length = (int)Math.Pow(2, objInfo);
return new NSNumber(CopyOfRange(bytes, offset + 1, offset + 1 + length), NSNumber.INTEGER);
}
case 0x2: {
case 0x2:
{
//real
int length = (int) Math.Pow(2, objInfo);
int length = (int)Math.Pow(2, objInfo);
return new NSNumber(CopyOfRange(bytes, offset + 1, offset + 1 + length), NSNumber.REAL);
}
case 0x3: {
case 0x3:
{
//Date
if (objInfo != 0x3) {
throw new PropertyListFormatException("The given binary property list contains a date object of an unknown type ("+objInfo+")");
if (objInfo != 0x3)
{
throw new PropertyListFormatException("The given binary property list contains a date object of an unknown type (" + objInfo + ")");
}
return new NSDate(CopyOfRange(bytes, offset + 1, offset + 9));
}
case 0x4: {
case 0x4:
{
//Data
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
@@ -260,7 +283,8 @@ namespace Claunia.PropertyList
return new NSData(CopyOfRange(bytes, offset + dataoffset, offset + dataoffset + length));
}
case 0x5: {
case 0x5:
{
//ASCII String
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
@@ -268,7 +292,8 @@ namespace Claunia.PropertyList
return new NSString(CopyOfRange(bytes, offset + stroffset, offset + stroffset + length), "ASCII");
}
case 0x6: {
case 0x6:
{
//UTF-16-BE String
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
@@ -278,58 +303,66 @@ namespace Claunia.PropertyList
length *= 2;
return new NSString(CopyOfRange(bytes, offset + stroffset, offset + stroffset + length), "UTF-16BE");
}
case 0x8: {
case 0x8:
{
//UID
int length = objInfo + 1;
return new UID(obj.ToString(), CopyOfRange(bytes, offset + 1, offset + 1 + length));
}
case 0xA: {
case 0xA:
{
//Array
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int arrayoffset = lenAndoffset[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));
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));
}
return array;
}
case 0xB: {
case 0xB:
{
//Ordered set
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int contentOffset = lenAndoffset[1];
NSSet set = new NSSet(true);
for (int i = 0; i < length; i++) {
int objRef = (int) ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + i * objectRefSize,
offset + contentOffset + (i + 1) * objectRefSize));
for (int i = 0; i < length; i++)
{
int objRef = (int)ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + i * objectRefSize,
offset + contentOffset + (i + 1) * objectRefSize));
set.AddObject(ParseObject(objRef));
}
return set;
}
case 0xC: {
case 0xC:
{
//Set
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
int contentOffset = lenAndoffset[1];
NSSet set = new NSSet();
for (int i = 0; i < length; i++) {
int objRef = (int) ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + i * objectRefSize,
offset + contentOffset + (i + 1) * objectRefSize));
for (int i = 0; i < length; i++)
{
int objRef = (int)ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + i * objectRefSize,
offset + contentOffset + (i + 1) * objectRefSize));
set.AddObject(ParseObject(objRef));
}
return set;
}
case 0xD: {
case 0xD:
{
//Dictionary
int[] lenAndoffset = ReadLengthAndOffset(objInfo, offset);
int length = lenAndoffset[0];
@@ -337,20 +370,22 @@ namespace Claunia.PropertyList
//System.out.println("Parsing dictionary #"+obj);
NSDictionary dict = new NSDictionary();
for (int i = 0; i < length; i++) {
int keyRef = (int) ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + i * objectRefSize,
offset + contentOffset + (i + 1) * objectRefSize));
int valRef = (int) ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + (length * objectRefSize) + i * objectRefSize,
offset + contentOffset + (length * objectRefSize) + (i + 1) * objectRefSize));
for (int i = 0; i < length; i++)
{
int keyRef = (int)ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + i * objectRefSize,
offset + contentOffset + (i + 1) * objectRefSize));
int valRef = (int)ParseUnsignedInt(CopyOfRange(bytes,
offset + contentOffset + (length * objectRefSize) + i * objectRefSize,
offset + contentOffset + (length * objectRefSize) + (i + 1) * objectRefSize));
NSObject key = ParseObject(keyRef);
NSObject val = ParseObject(valRef);
dict.Add(key.ToString(), val);
}
return dict;
}
default: {
default:
{
Console.WriteLine("WARNING: The given binary property list contains an object of unknown type (" + objType + ")");
break;
}
@@ -364,33 +399,39 @@ namespace Claunia.PropertyList
/// <returns>An array with the length two. First entry is the length, second entry the offset at which the content starts.</returns>
/// <param name="objInfo">Object information byte.</param>
/// <param name="offset">Offset in the byte array at which the object is located.</param>
private int[] ReadLengthAndOffset(int objInfo, int offset) {
private int[] ReadLengthAndOffset(int objInfo, int offset)
{
int length = objInfo;
int stroffset = 1;
if (objInfo == 0xF) {
if (objInfo == 0xF)
{
int int_type = bytes[offset + 1];
int intType = (int_type & 0xF0) >> 4;
if (intType != 0x1) {
if (intType != 0x1)
{
Console.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);
int intLength = (int)Math.Pow(2, intInfo);
stroffset = 2 + intLength;
if (intLength < 3) {
length = (int) ParseUnsignedInt(CopyOfRange(bytes, offset + 2, offset + 2 + intLength));
} else {
if (intLength < 3)
{
length = (int)ParseUnsignedInt(CopyOfRange(bytes, offset + 2, offset + 2 + intLength));
}
else
{
// BigInteger is Little-Endian in .NET, swap the thing.
// Also BigInteger is of .NET 4.0, maybe there's a better way to do it.
byte[] bigEBigInteger = CopyOfRange(bytes, offset + 2, offset + 2 + intLength);
byte[] litEBigInteger = new byte[bigEBigInteger.Length + 1];
for(int i = 0, j = bigEBigInteger.Length-1; i < bigEBigInteger.Length && j >= 0; i++, j--)
for (int i = 0, j = bigEBigInteger.Length - 1; i < bigEBigInteger.Length && j >= 0; i++, j--)
litEBigInteger[i] = bigEBigInteger[j];
litEBigInteger[litEBigInteger.Length - 1] = (byte)0x00; // Be sure to get unsigned BigInteger
length = (int) new System.Numerics.BigInteger(litEBigInteger);
length = (int)new System.Numerics.BigInteger(litEBigInteger);
}
}
return new int[]{length, stroffset};
return new int[]{ length, stroffset };
}
/// <summary>
@@ -398,9 +439,11 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The byte array containing the unsigned integer.</returns>
/// <param name="bytes">The unsigned integer represented by the given bytes.</param>
public static long ParseUnsignedInt(byte[] bytes) {
public static long ParseUnsignedInt(byte[] bytes)
{
long l = 0;
foreach (byte b in bytes) {
foreach (byte b in bytes)
{
l <<= 8;
l |= b & 0xFF;
}
@@ -415,9 +458,11 @@ namespace Claunia.PropertyList
/// <param name="bytes">The byte array containing the unsigned integer.</param>
/// <param name="startIndex">Beginning of the unsigned int in the byte array.</param>
/// <param name="endIndex">End of the unsigned int in the byte array.</param>
public static long ParseUnsignedInt(byte[] bytes, int startIndex, int endIndex) {
public static long ParseUnsignedInt(byte[] bytes, int startIndex, int endIndex)
{
long l = 0;
for (int i = startIndex; i < endIndex; i++) {
for (int i = startIndex; i < endIndex; i++)
{
l <<= 8;
l |= bytes[i] & 0xFF;
}
@@ -430,9 +475,11 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The long integer represented by the given bytes.</returns>
/// <param name="bytes">The bytes representing the long integer.</param>
public static long ParseLong(byte[] bytes) {
public static long ParseLong(byte[] bytes)
{
long l = 0;
foreach (byte b in bytes) {
foreach (byte b in bytes)
{
l <<= 8;
l |= b & 0xFF;
}
@@ -446,9 +493,11 @@ namespace Claunia.PropertyList
/// <param name="bytes">The bytes representing the long integer.</param>
/// <param name="startIndex">Beginning of the long in the byte array.</param>
/// <param name="endIndex">End of the long in the byte array.</param>
public static long ParseLong(byte[] bytes, int startIndex, int endIndex) {
public static long ParseLong(byte[] bytes, int startIndex, int endIndex)
{
long l = 0;
for (int i = startIndex; i < endIndex; i++) {
for (int i = startIndex; i < endIndex; i++)
{
l <<= 8;
l |= bytes[i] & 0xFF;
}
@@ -460,12 +509,18 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The double represented by the given bytes.</returns>
/// <param name="bytes">The bytes representing the double.</param>
public static double ParseDouble(byte[] bytes) {
if (bytes.Length == 8) {
public static double ParseDouble(byte[] bytes)
{
if (bytes.Length == 8)
{
return BitConverter.Int64BitsToDouble(ParseLong(bytes));
} else if (bytes.Length == 4) {
}
else if (bytes.Length == 4)
{
return BitConverter.ToSingle(BitConverter.GetBytes(ParseLong(bytes)), 0);
} else {
}
else
{
throw new ArgumentException("bad byte array length " + bytes.Length);
}
}
@@ -477,13 +532,19 @@ namespace Claunia.PropertyList
/// <param name="bytes">The bytes representing the double.</param>
/// <param name="startIndex">Beginning of the double in the byte array.</param>
/// <param name="endIndex">End of the double in the byte array.</param>
public static double ParseDouble(byte[] bytes, int startIndex, int endIndex) {
if (endIndex - startIndex == 8) {
public static double ParseDouble(byte[] bytes, int startIndex, int endIndex)
{
if (endIndex - startIndex == 8)
{
return BitConverter.Int64BitsToDouble(ParseLong(bytes, startIndex, endIndex));
} else if (endIndex - startIndex == 4) {
}
else if (endIndex - startIndex == 4)
{
return BitConverter.ToSingle(BitConverter.GetBytes(ParseLong(bytes, startIndex, endIndex)), 0);
} else {
throw new ArgumentException("endIndex ("+endIndex+") - startIndex ("+startIndex+") != 4 or 8");
}
else
{
throw new ArgumentException("endIndex (" + endIndex + ") - startIndex (" + startIndex + ") != 4 or 8");
}
}
@@ -494,9 +555,11 @@ namespace Claunia.PropertyList
/// <param name="src">The source array.</param>
/// <param name="startIndex">The index from which to start copying.</param>
/// <param name="endIndex">The index until which to copy.</param>
public static byte[] CopyOfRange(byte[] src, int startIndex, int endIndex) {
public static byte[] CopyOfRange(byte[] src, int startIndex, int endIndex)
{
int length = endIndex - startIndex;
if (length < 0) {
if (length < 0)
{
throw new ArgumentOutOfRangeException("startIndex (" + startIndex + ")" + " > endIndex (" + endIndex + ")");
}
byte[] dest = new byte[length];

View File

@@ -49,30 +49,40 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>Version code</returns>
/// <param name="root">Object root.</param>
private static int GetMinimumRequiredVersion(NSObject root) {
private static int GetMinimumRequiredVersion(NSObject root)
{
int minVersion = VERSION_00;
if (root == null) {
if (root == null)
{
minVersion = VERSION_10;
}
if (root is NSDictionary) {
NSDictionary dict = (NSDictionary) root;
foreach (NSObject o in dict.GetDictionary().Values) {
if (root is NSDictionary)
{
NSDictionary dict = (NSDictionary)root;
foreach (NSObject o in dict.GetDictionary().Values)
{
int v = GetMinimumRequiredVersion(o);
if (v > minVersion)
minVersion = v;
}
} else if (root is NSArray) {
NSArray array = (NSArray) root;
foreach (NSObject o in array.GetArray()) {
}
else if (root is NSArray)
{
NSArray array = (NSArray)root;
foreach (NSObject o in array.GetArray())
{
int v = GetMinimumRequiredVersion(o);
if (v > minVersion)
minVersion = v;
}
} else if (root is NSSet) {
}
else if (root is NSSet)
{
//Sets are only allowed in property lists v1+
minVersion = VERSION_10;
NSSet set = (NSSet) root;
foreach (NSObject o in set.AllObjects()) {
NSSet set = (NSSet)root;
foreach (NSObject o in set.AllObjects())
{
int v = GetMinimumRequiredVersion(o);
if (v > minVersion)
minVersion = v;
@@ -87,7 +97,8 @@ namespace Claunia.PropertyList
/// <param name="file">the file to write to</param>
/// <param name="root">the source of the data to write to the file</param>
/// <exception cref="IOException"></exception>
public static void Write(FileInfo file, NSObject root) {
public static void Write(FileInfo file, NSObject root)
{
FileStream fous = file.OpenWrite();
Write(fous, root);
fous.Close();
@@ -99,12 +110,14 @@ namespace Claunia.PropertyList
/// <param name="outStream">the stream to write to</param>
/// <param name="root">the source of the data to write to the stream</param>
/// <exception cref="IOException"></exception>
public static void Write(Stream outStream, NSObject root) {
public static void Write(Stream outStream, NSObject root)
{
int minVersion = GetMinimumRequiredVersion(root);
if (minVersion > VERSION_00) {
if (minVersion > VERSION_00)
{
string versionString = ((minVersion == VERSION_10) ? "v1.0" : ((minVersion == VERSION_15) ? "v1.5" : ((minVersion == VERSION_20) ? "v2.0" : "v0.0")));
throw new IOException("The given property list structure cannot be saved. " +
"The required version of the binary format (" + versionString + ") is not yet supported.");
"The required version of the binary format (" + versionString + ") is not yet supported.");
}
BinaryPropertyListWriter w = new BinaryPropertyListWriter(outStream, minVersion);
w.Write(root);
@@ -117,7 +130,8 @@ namespace Claunia.PropertyList
/// <returns>The byte array containing the serialized property list</returns>
/// <param name="root">The root object of the property list</param>
/// <exception cref="IOException"></exception>
public static byte[] WriteToArray(NSObject root) {
public static byte[] WriteToArray(NSObject root)
{
MemoryStream bout = new MemoryStream();
Write(bout, root);
return bout.ToArray();
@@ -140,35 +154,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) {
BinaryPropertyListWriter(Stream outStr)
{
outStream = outStr;
}
BinaryPropertyListWriter(Stream outStr, int version) {
BinaryPropertyListWriter(Stream outStr, int version)
{
this.version = version;
outStream = outStr;
}
void Write(NSObject root) {
void Write(NSObject root)
{
// magic bytes
Write(new byte[]{(byte)'b', (byte)'p', (byte)'l', (byte)'i', (byte)'s', (byte)'t'});
Write(new byte[]{ (byte)'b', (byte)'p', (byte)'l', (byte)'i', (byte)'s', (byte)'t' });
//version
switch (version) {
case VERSION_00: {
Write(new byte[]{(byte)'0', (byte)'0'});
switch (version)
{
case VERSION_00:
{
Write(new byte[]{ (byte)'0', (byte)'0' });
break;
}
case VERSION_10: {
Write(new byte[]{(byte)'1', (byte)'0'});
case VERSION_10:
{
Write(new byte[]{ (byte)'1', (byte)'0' });
break;
}
case VERSION_15: {
Write(new byte[]{(byte)'1', (byte)'5'});
case VERSION_15:
{
Write(new byte[]{ (byte)'1', (byte)'5' });
break;
}
case VERSION_20: {
Write(new byte[]{(byte)'2', (byte)'0'});
case VERSION_20:
{
Write(new byte[]{ (byte)'2', (byte)'0' });
break;
}
}
@@ -182,13 +204,17 @@ namespace Claunia.PropertyList
long[] offsets = new long[idMap.Count];
// write each object, save offset
foreach (KeyValuePair<NSObject, int> entry in idMap) {
foreach (KeyValuePair<NSObject, int> entry in idMap)
{
NSObject obj = entry.Key;
int id = entry.Value;
offsets[id] = count;
if (obj == null) {
if (obj == null)
{
Write(0x00);
} else {
}
else
{
obj.ToBinary(this);
}
}
@@ -196,11 +222,13 @@ namespace Claunia.PropertyList
// write offset table
long offsetTableOffset = count;
int offsetSizeInBytes = ComputeOffsetSizeInBytes(count);
foreach (long offset in offsets) {
foreach (long offset in offsets)
{
WriteBytes(offset, offsetSizeInBytes);
}
if (version != VERSION_15) {
if (version != VERSION_15)
{
// write trailer
// 6 null bytes
Write(new byte[6]);
@@ -221,80 +249,105 @@ namespace Claunia.PropertyList
outStream.Flush();
}
internal void AssignID(NSObject obj) {
if (!idMap.ContainsKey(obj)) {
internal void AssignID(NSObject obj)
{
if (!idMap.ContainsKey(obj))
{
idMap.Add(obj, idMap.Count);
}
}
internal int GetID(NSObject obj) {
internal int GetID(NSObject obj)
{
int ID;
idMap.TryGetValue(obj, out ID);
return ID;
}
private static int ComputeIdSizeInBytes(int numberOfIds) {
if (numberOfIds < 256) return 1;
if (numberOfIds < 65536) return 2;
private static int ComputeIdSizeInBytes(int numberOfIds)
{
if (numberOfIds < 256)
return 1;
if (numberOfIds < 65536)
return 2;
return 4;
}
private int ComputeOffsetSizeInBytes(long maxOffset) {
if (maxOffset < 256) return 1;
if (maxOffset < 65536) return 2;
if (maxOffset < 4294967296L) return 4;
private int ComputeOffsetSizeInBytes(long maxOffset)
{
if (maxOffset < 256)
return 1;
if (maxOffset < 65536)
return 2;
if (maxOffset < 4294967296L)
return 4;
return 8;
}
internal void WriteIntHeader(int kind, int value) {
internal void WriteIntHeader(int kind, int value)
{
if (value <= 0)
throw new ArgumentException("value must be greater than 0", "value");
if (value < 15) {
if (value < 15)
{
Write((kind << 4) + value);
} else if (value < 256) {
}
else if (value < 256)
{
Write((kind << 4) + 15);
Write(0x10);
WriteBytes(value, 1);
} else if (value < 65536) {
}
else if (value < 65536)
{
Write((kind << 4) + 15);
Write(0x11);
WriteBytes(value, 2);
} else {
}
else
{
Write((kind << 4) + 15);
Write(0x12);
WriteBytes(value, 4);
}
}
internal void Write(int b) {
byte[] bBytes= new byte[1];
internal void Write(int b)
{
byte[] bBytes = new byte[1];
bBytes[0] = (byte)b;
outStream.Write(bBytes, 0, 1);
count++;
}
internal void Write(byte[] bytes) {
internal void Write(byte[] bytes)
{
outStream.Write(bytes, 0, bytes.Length);
count += bytes.Length;
}
internal void WriteBytes(long value, int bytes) {
internal void WriteBytes(long value, int bytes)
{
// write low-order bytes big-endian style
for (int i = bytes - 1; i >= 0; i--) {
Write((int) (value >> (8 * i)));
for (int i = bytes - 1; i >= 0; i--)
{
Write((int)(value >> (8 * i)));
}
}
internal void WriteID(int id) {
internal void WriteID(int id)
{
WriteBytes(id, idSizeInBytes);
}
internal void WriteLong(long value) {
internal void WriteLong(long value)
{
WriteBytes(value, 8);
}
internal void WriteDouble(double value) {
internal void WriteDouble(double value)
{
WriteLong(BitConverter.DoubleToInt64Bits(value));
}
}

View File

@@ -1,3 +1,22 @@
2015-02-20 Natalia Portillo <claunia@claunia.com>
* UID.cs:
* NSSet.cs:
* NSDate.cs:
* NSData.cs:
* NSArray.cs:
* NSString.cs:
* NSObject.cs:
* NSNumber.cs:
* NSDictionary.cs:
* PropertyListParser.cs:
* XmlPropertyListParser.cs:
* ASCIIPropertyListParser.cs:
* BinaryPropertyListWriter.cs:
* BinaryPropertyListParser.cs:
* PropertyListFormatException.cs:
Reformat code.
2015-02-19 Natalia Portillo <claunia@claunia.com>
* UID.cs:

View File

@@ -236,16 +236,20 @@ namespace Claunia.PropertyList
xml.Append("</array>");
}
internal override void AssignIDs(BinaryPropertyListWriter outPlist) {
internal override void AssignIDs(BinaryPropertyListWriter outPlist)
{
base.AssignIDs(outPlist);
foreach (NSObject obj in array) {
foreach (NSObject obj in array)
{
obj.AssignIDs(outPlist);
}
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
outPlist.WriteIntHeader(0xA, array.Length);
foreach (NSObject obj in array) {
foreach (NSObject obj in array)
{
outPlist.WriteID(outPlist.GetID(obj));
}
}
@@ -290,7 +294,7 @@ namespace Claunia.PropertyList
{
Type objClass = array[i].GetType();
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
&& indexOfLastNewLine != ascii.Length)
&& indexOfLastNewLine != ascii.Length)
{
ascii.Append(NEWLINE);
indexOfLastNewLine = ascii.Length;
@@ -324,7 +328,7 @@ namespace Claunia.PropertyList
{
Type objClass = array[i].GetType();
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
&& indexOfLastNewLine != ascii.Length)
&& indexOfLastNewLine != ascii.Length)
{
ascii.Append(NEWLINE);
indexOfLastNewLine = ascii.Length;

View File

@@ -41,7 +41,8 @@ namespace Claunia.PropertyList
/// Creates the NSData object from the binary representation of it.
/// </summary>
/// <param name="bytes">The raw data contained in the NSData object.</param>
public NSData(byte[] bytes) {
public NSData(byte[] bytes)
{
this.bytes = bytes;
}
@@ -50,7 +51,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="base64">The Base64 encoded contents of the NSData object.</param>
/// <exception cref="FormatException">When the given string is not a proper Base64 formatted string.</exception>
public NSData(string base64) {
public NSData(string base64)
{
bytes = Convert.FromBase64String(base64);
}
@@ -60,8 +62,9 @@ namespace Claunia.PropertyList
/// <param name="file">The file containing the data.</param>
/// <exception cref="FileNotFoundException">If the file could not be found.</exception>
/// <exception cref="IOException">If the file could not be read.</exception>
public NSData(FileInfo file) {
bytes = new byte[(int) file.Length];
public NSData(FileInfo file)
{
bytes = new byte[(int)file.Length];
FileStream raf = file.OpenRead();
raf.Read(bytes, 0, (int)file.Length);
raf.Close();
@@ -71,8 +74,10 @@ namespace Claunia.PropertyList
/// The bytes contained in this NSData object.
/// </summary>
/// <value>The data as bytes</value>
public byte[] Bytes {
get {
public byte[] Bytes
{
get
{
return bytes;
}
}
@@ -81,8 +86,10 @@ namespace Claunia.PropertyList
/// Gets the amount of data stored in this object.
/// </summary>
/// <value>The number of bytes contained in this object.</value>
public int Length {
get {
public int Length
{
get
{
return bytes.Length;
}
}
@@ -92,7 +99,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="buf">The byte buffer which will contain the data</param>
/// <param name="length">The amount of data to copy</param>
public void GetBytes(MemoryStream buf, int length) {
public void GetBytes(MemoryStream buf, int length)
{
buf.Write(bytes, 0, Math.Min(bytes.Length, length));
}
@@ -102,7 +110,8 @@ namespace Claunia.PropertyList
/// <param name="buf">The byte buffer which will contain the data</param>
/// <param name="rangeStart">The start index.</param>
/// <param name="rangeStop">The stop index.</param>
public void GetBytes(MemoryStream buf, int rangeStart, int rangeStop) {
public void GetBytes(MemoryStream buf, int rangeStart, int rangeStop)
{
buf.Write(bytes, rangeStart, Math.Min(bytes.Length, rangeStop));
}
@@ -110,26 +119,31 @@ namespace Claunia.PropertyList
/// Gets the Base64 encoded data contained in this NSData object.
/// </summary>
/// <returns>The Base64 encoded data as a <c>string</c>.</returns>
public string GetBase64EncodedData() {
public string GetBase64EncodedData()
{
return Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
}
public override bool Equals(Object obj) {
return obj.GetType().Equals(GetType()) && ArrayEquals(((NSData) obj).bytes, bytes);
public override bool Equals(Object obj)
{
return obj.GetType().Equals(GetType()) && ArrayEquals(((NSData)obj).bytes, bytes);
}
public override int GetHashCode() {
public override int GetHashCode()
{
int hash = 5;
hash = 67 * hash + bytes.GetHashCode();
return hash;
}
internal override void ToXml(StringBuilder xml, int level) {
internal override void ToXml(StringBuilder xml, int level)
{
Indent(xml, level);
xml.Append("<data>");
xml.Append(NSObject.NEWLINE);
string base64 = GetBase64EncodedData();
foreach (string line in base64.Split('\n')) {
foreach (string line in base64.Split('\n'))
{
Indent(xml, level + 1);
xml.Append(line);
xml.Append(NSObject.NEWLINE);
@@ -138,35 +152,42 @@ namespace Claunia.PropertyList
xml.Append("</data>");
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
outPlist.WriteIntHeader(0x4, bytes.Length);
outPlist.Write(bytes);
}
internal override void ToASCII(StringBuilder ascii, int level) {
internal override void ToASCII(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append(ASCIIPropertyListParser.DATA_BEGIN_TOKEN);
int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE);
for (int i = 0; i < bytes.Length; i++) {
for (int i = 0; i < bytes.Length; i++)
{
int b = bytes[i] & 0xFF;
ascii.Append(String.Format("{0:x2}", b));
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) {
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
{
ascii.Append(NEWLINE);
indexOfLastNewLine = ascii.Length;
} else if ((i + 1) % 2 == 0 && i != bytes.Length - 1) {
}
else if ((i + 1) % 2 == 0 && i != bytes.Length - 1)
{
ascii.Append(" ");
}
}
ascii.Append(ASCIIPropertyListParser.DATA_END_TOKEN);
}
internal override void ToASCIIGnuStep(StringBuilder ascii, int level) {
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
{
ToASCII(ascii, level);
}
public override bool Equals(NSObject obj)
{
if(!(obj is NSData))
if (!(obj is NSData))
return false;
return ArrayEquals(bytes, ((NSData)obj).Bytes);

View File

@@ -49,10 +49,14 @@ namespace Claunia.PropertyList
/// <returns>The parsed Date</returns>
/// <param name="textRepresentation">The date string as found in the XML property list</param>
/// <exception cref="FormatException">Given string cannot be parsed</exception>
private static DateTime ParseDateString(string textRepresentation) {
try {
private static DateTime ParseDateString(string textRepresentation)
{
try
{
return DateTime.ParseExact(textRepresentation, sdfDefault, provider);
} catch (FormatException ex) {
}
catch (FormatException ex)
{
return DateTime.ParseExact(textRepresentation, sdfGnuStep, provider);
}
}
@@ -63,7 +67,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="date">The date which should be represented.</param>
/// <returns>The string representation of the date.</returns>
private static string MakeDateString(DateTime date) {
private static string MakeDateString(DateTime date)
{
return date.ToString(sdfDefault);
}
@@ -74,7 +79,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="date">The date which should be represented.</param>
/// <returns>The string representation of the date.</returns>
private static string MakeDateStringGnuStep(DateTime date) {
private static string MakeDateStringGnuStep(DateTime date)
{
return date.ToString(sdfGnuStep);
}
@@ -82,7 +88,8 @@ namespace Claunia.PropertyList
/// Creates a date from its binary representation.
/// </summary>
/// <param name="bytes">bytes The date bytes</param>
public NSDate(byte[] bytes) {
public NSDate(byte[] bytes)
{
//dates are 8 byte big-endian double, seconds since the epoch
date = EPOCH.AddSeconds(BinaryPropertyListParser.ParseDouble(bytes));
}
@@ -93,7 +100,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="textRepresentation">The textual representation of the date (ISO 8601 format)</param>
/// <exception cref="FormatException">When the date could not be parsed, i.e. it does not match the expected pattern.</exception>
public NSDate(String textRepresentation) {
public NSDate(String textRepresentation)
{
date = ParseDateString(textRepresentation);
}
@@ -101,7 +109,8 @@ namespace Claunia.PropertyList
/// Creates a NSDate from a .NET DateTime
/// </summary>
/// <param name="d">The date</param>
public NSDate(DateTime d) {
public NSDate(DateTime d)
{
if (d == null)
throw new ArgumentException("Date cannot be null", "d");
date = d;
@@ -119,22 +128,26 @@ namespace Claunia.PropertyList
}
}
public override bool Equals(Object obj) {
return obj.GetType().Equals(GetType()) && date.Equals(((NSDate) obj).Date);
public override bool Equals(Object obj)
{
return obj.GetType().Equals(GetType()) && date.Equals(((NSDate)obj).Date);
}
public override int GetHashCode() {
public override int GetHashCode()
{
return date.GetHashCode();
}
internal override void ToXml(StringBuilder xml, int level) {
internal override void ToXml(StringBuilder xml, int level)
{
Indent(xml, level);
xml.Append("<date>");
xml.Append(MakeDateString(date));
xml.Append("</date>");
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
outPlist.Write(0x33);
outPlist.WriteDouble((date - EPOCH).TotalSeconds);
}
@@ -143,18 +156,21 @@ namespace Claunia.PropertyList
/// Generates a string representation of the date.
/// </summary>
/// <returns>A string representation of the date.</returns>
public override String ToString() {
public override String ToString()
{
return date.ToString();
}
internal override void ToASCII(StringBuilder ascii, int level) {
internal override void ToASCII(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append("\"");
ascii.Append(MakeDateString(date));
ascii.Append("\"");
}
internal override void ToASCIIGnuStep(StringBuilder ascii, int level) {
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append("<*D");
ascii.Append(MakeDateStringGnuStep(date));

View File

@@ -45,7 +45,8 @@ namespace Claunia.PropertyList
/// <summary>
/// Creates a new empty NSDictionary.
/// </summary>
public NSDictionary() {
public NSDictionary()
{
dict = new Dictionary<string, NSObject>();
}
@@ -55,7 +56,8 @@ namespace Claunia.PropertyList
/// dictionary.
/// </summary>
/// <returns>The hashmap which is used by this dictionary to store its contents.</returns>
public Dictionary<string, NSObject> GetDictionary() {
public Dictionary<string, NSObject> GetDictionary()
{
return dict;
}
@@ -64,14 +66,16 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The object.</returns>
/// <param name="key">The key.</param>
public NSObject ObjectForKey(string key) {
public NSObject ObjectForKey(string key)
{
NSObject nso;
return dict.TryGetValue(key, out nso) ? nso : null;
}
public bool IsEmpty
{
get {
get
{
return dict.Count == 0;
}
}
@@ -88,12 +92,13 @@ namespace Claunia.PropertyList
public NSObject Get(Object key)
{
if(key is string)
if (key is string)
return ObjectForKey((string)key);
return null;
}
public bool ContainsValue(Object value) {
public bool ContainsValue(Object value)
{
if (value == null)
return false;
NSObject wrap = NSObject.Wrap(value);
@@ -106,8 +111,9 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="key">The key.</param>
/// <param name="obj">The value. Supported object types are numbers, byte-arrays, dates, strings and arrays or sets of those.</param>
public void Add(String key, Object obj) {
if(obj == null)
public void Add(String key, Object obj)
{
if (obj == null)
return;
Add(key, NSObject.Wrap(obj));
}
@@ -117,7 +123,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="key">The key.</param>
/// <param name="obj">The value.</param>
public void Add(string key, long obj) {
public void Add(string key, long obj)
{
Add(key, new NSNumber(obj));
}
@@ -126,7 +133,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="key">The key.</param>
/// <param name="obj">The value.</param>
public void Add(string key, double obj) {
public void Add(string key, double obj)
{
Add(key, new NSNumber(obj));
}
@@ -135,7 +143,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="key">The key.</param>
/// <param name="obj">The value.</param>
public void Add(string key, bool obj) {
public void Add(string key, bool obj)
{
Add(key, new NSNumber(obj));
}
@@ -144,10 +153,13 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="val">The value that will be searched for.</param>
/// <returns>Whether the key is contained in this dictionary.</returns>
public bool ContainsValue(string val) {
foreach (NSObject o in dict.Values) {
if (o.GetType().Equals(typeof(NSString))) {
NSString str = (NSString) o;
public bool ContainsValue(string val)
{
foreach (NSObject o in dict.Values)
{
if (o.GetType().Equals(typeof(NSString)))
{
NSString str = (NSString)o;
if (str.GetContent().Equals(val))
return true;
}
@@ -160,10 +172,13 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="val">The value that will be searched for.</param>
/// <returns>Whether the key is contained in this dictionary.</returns>
public bool ContainsValue(long val) {
foreach (NSObject o in dict.Values) {
if (o.GetType().Equals(typeof(NSNumber))) {
NSNumber num = (NSNumber) o;
public bool ContainsValue(long val)
{
foreach (NSObject o in dict.Values)
{
if (o.GetType().Equals(typeof(NSNumber)))
{
NSNumber num = (NSNumber)o;
if (num.isInteger() && num.ToInt() == val)
return true;
}
@@ -176,10 +191,13 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="val">The value that will be searched for.</param>
/// <returns>Whether the key is contained in this dictionary.</returns>
public bool ContainsValue(double val) {
foreach (NSObject o in dict.Values) {
if (o.GetType().Equals(typeof(NSNumber))) {
NSNumber num = (NSNumber) o;
public bool ContainsValue(double val)
{
foreach (NSObject o in dict.Values)
{
if (o.GetType().Equals(typeof(NSNumber)))
{
NSNumber num = (NSNumber)o;
if (num.isReal() && num.ToDouble() == val)
return true;
}
@@ -192,10 +210,13 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="val">The value that will be searched for.</param>
/// <returns>Whether the key is contained in this dictionary.</returns>
public bool ContainsValue(bool val) {
foreach (NSObject o in dict.Values) {
if (o.GetType().Equals(typeof(NSNumber))) {
NSNumber num = (NSNumber) o;
public bool ContainsValue(bool val)
{
foreach (NSObject o in dict.Values)
{
if (o.GetType().Equals(typeof(NSNumber)))
{
NSNumber num = (NSNumber)o;
if (num.isBoolean() && num.ToBool() == val)
return true;
}
@@ -208,10 +229,13 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="val">The value that will be searched for.</param>
/// <returns>Whether the key is contained in this dictionary.</returns>
public bool ContainsValue(DateTime val) {
foreach (NSObject o in dict.Values) {
if (o.GetType().Equals(typeof(NSDate))) {
NSDate dat = (NSDate) o;
public bool ContainsValue(DateTime val)
{
foreach (NSObject o in dict.Values)
{
if (o.GetType().Equals(typeof(NSDate)))
{
NSDate dat = (NSDate)o;
if (dat.Date.Equals(val))
return true;
}
@@ -224,10 +248,13 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="val">The value that will be searched for.</param>
/// <returns>Whether the key is contained in this dictionary.</returns>
public bool ContainsValue(byte[] val) {
foreach (NSObject o in dict.Values) {
if (o.GetType().Equals(typeof(NSData))) {
NSData dat = (NSData) o;
public bool ContainsValue(byte[] val)
{
foreach (NSObject o in dict.Values)
{
if (o.GetType().Equals(typeof(NSData)))
{
NSData dat = (NSData)o;
if (ArrayEquals(dat.Bytes, val))
return true;
}
@@ -235,9 +262,10 @@ namespace Claunia.PropertyList
return false;
}
public override bool Equals(Object obj) {
bool foo = this.Equals((NSDictionary) obj);
return (obj.GetType().Equals(GetType()) && ((NSDictionary) obj).dict.Equals(dict));
public override bool Equals(Object obj)
{
bool foo = this.Equals((NSDictionary)obj);
return (obj.GetType().Equals(GetType()) && ((NSDictionary)obj).dict.Equals(dict));
}
public override bool Equals(NSObject obj)
@@ -263,26 +291,32 @@ namespace Claunia.PropertyList
return true;
}
public override int GetHashCode() {
public override int GetHashCode()
{
int hash = 7;
hash = 83 * hash + (this.dict != null ? this.dict.GetHashCode() : 0);
return hash;
}
internal override void ToXml(StringBuilder xml, int level) {
internal override void ToXml(StringBuilder xml, int level)
{
Indent(xml, level);
xml.Append("<dict>");
xml.Append(NSObject.NEWLINE);
foreach(KeyValuePair<string, NSObject> kvp in dict) {
foreach (KeyValuePair<string, NSObject> kvp in dict)
{
Indent(xml, level + 1);
xml.Append("<key>");
//According to http://www.w3.org/TR/REC-xml/#syntax node values must not
//contain the characters < or &. Also the > character should be escaped.
if (kvp.Key.Contains("&") || kvp.Key.Contains("<") || kvp.Key.Contains(">")) {
if (kvp.Key.Contains("&") || kvp.Key.Contains("<") || kvp.Key.Contains(">"))
{
xml.Append("<![CDATA[");
xml.Append(kvp.Key.Replace("]]>", "]]]]><![CDATA[>"));
xml.Append("]]>");
} else {
}
else
{
xml.Append(kvp.Key);
}
xml.Append("</key>");
@@ -294,20 +328,25 @@ namespace Claunia.PropertyList
xml.Append("</dict>");
}
internal override void AssignIDs(BinaryPropertyListWriter outPlist) {
internal override void AssignIDs(BinaryPropertyListWriter outPlist)
{
base.AssignIDs(outPlist);
foreach (KeyValuePair<string, NSObject> entry in dict) {
foreach (KeyValuePair<string, NSObject> entry in dict)
{
new NSString(entry.Key).AssignIDs(outPlist);
entry.Value.AssignIDs(outPlist);
}
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
outPlist.WriteIntHeader(0xD, dict.Count);
foreach (KeyValuePair<String, NSObject> entry in dict) {
foreach (KeyValuePair<String, NSObject> entry in dict)
{
outPlist.WriteID(outPlist.GetID(new NSString(entry.Key)));
}
foreach (KeyValuePair<String, NSObject> entry in dict) {
foreach (KeyValuePair<String, NSObject> entry in dict)
{
outPlist.WriteID(outPlist.GetID(entry.Value));
}
}
@@ -319,7 +358,8 @@ namespace Claunia.PropertyList
/// Property List Programming Guide - Old-Style ASCII Property Lists</a>.
/// </summary>
/// <returns>ASCII representation of this object.</returns>
public string ToASCIIPropertyList() {
public string ToASCIIPropertyList()
{
StringBuilder ascii = new StringBuilder();
ToASCII(ascii, 0);
ascii.Append(NEWLINE);
@@ -333,28 +373,34 @@ namespace Claunia.PropertyList
/// GnuStep - NSPropertyListSerialization class documentation</a>
/// </summary>
/// <returns>GnuStep ASCII representation of this object.</returns>
public string ToGnuStepASCIIPropertyList() {
public string ToGnuStepASCIIPropertyList()
{
StringBuilder ascii = new StringBuilder();
ToASCIIGnuStep(ascii, 0);
ascii.Append(NEWLINE);
return ascii.ToString();
}
internal override void ToASCII(StringBuilder ascii, int level) {
internal override void ToASCII(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append(ASCIIPropertyListParser.DICTIONARY_BEGIN_TOKEN);
ascii.Append(NEWLINE);
foreach (string key in Keys) {
foreach (string key in Keys)
{
NSObject val = ObjectForKey(key);
Indent(ascii, level + 1);
ascii.Append("\"");
ascii.Append(NSString.EscapeStringForASCII(key));
ascii.Append("\" =");
Type objClass = val.GetType();
if (objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData))) {
if (objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
{
ascii.Append(NEWLINE);
val.ToASCII(ascii, level + 2);
} else {
}
else
{
ascii.Append(" ");
val.ToASCII(ascii, 0);
}
@@ -365,21 +411,26 @@ namespace Claunia.PropertyList
ascii.Append(ASCIIPropertyListParser.DICTIONARY_END_TOKEN);
}
internal override void ToASCIIGnuStep(StringBuilder ascii, int level) {
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append(ASCIIPropertyListParser.DICTIONARY_BEGIN_TOKEN);
ascii.Append(NEWLINE);
foreach (string key in Keys) {
foreach (string key in Keys)
{
NSObject val = ObjectForKey(key);
Indent(ascii, level + 1);
ascii.Append("\"");
ascii.Append(NSString.EscapeStringForASCII(key));
ascii.Append("\" =");
Type objClass = val.GetType();
if (objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData))) {
if (objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
{
ascii.Append(NEWLINE);
val.ToASCIIGnuStep(ascii, level + 2);
} else {
}
else
{
ascii.Append(" ");
val.ToASCIIGnuStep(ascii, 0);
}
@@ -391,6 +442,7 @@ namespace Claunia.PropertyList
}
#region IDictionary implementation
public void Add(string key, NSObject value)
{
dict.Add(key, value);
@@ -416,7 +468,7 @@ namespace Claunia.PropertyList
return dict.TryGetValue(key, out value);
}
public NSObject this[string index]
public NSObject this [string index]
{
get
{
@@ -427,6 +479,7 @@ namespace Claunia.PropertyList
dict[index] = value;
}
}
public ICollection<string> Keys
{
get
@@ -434,6 +487,7 @@ namespace Claunia.PropertyList
return dict.Keys;
}
}
public ICollection<NSObject> Values
{
get
@@ -441,28 +495,36 @@ namespace Claunia.PropertyList
return dict.Values;
}
}
#endregion
#region ICollection implementation
public void Add(KeyValuePair<string, NSObject> item)
{
dict.Add(item.Key, item.Value);
}
public void Clear()
{
dict.Clear();
}
public bool Contains(KeyValuePair<string, NSObject> item)
{
return dict.ContainsKey(item.Key);
}
public void CopyTo(KeyValuePair<string, NSObject>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<string, NSObject> item)
{
return dict.Remove(item.Key);
}
public int Count
{
get
@@ -470,6 +532,7 @@ namespace Claunia.PropertyList
return dict.Count;
}
}
public bool IsReadOnly
{
get
@@ -477,18 +540,25 @@ namespace Claunia.PropertyList
return false;
}
}
#endregion
#region IEnumerable implementation
public IEnumerator<KeyValuePair<string, NSObject>> GetEnumerator()
{
return dict.GetEnumerator();
}
#endregion
#region IEnumerable implementation
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return dict.GetEnumerator();
}
#endregion
}
}

View File

@@ -69,18 +69,23 @@ namespace Claunia.PropertyList
/// <param name="type">The type of number</param>
/// <seealso cref="INTEGER"/>
/// <seealso cref="REAL"/>
public NSNumber(byte[] bytes, int type) {
switch (type) {
case INTEGER: {
public NSNumber(byte[] bytes, int type)
{
switch (type)
{
case INTEGER:
{
doubleValue = longValue = BinaryPropertyListParser.ParseLong(bytes);
break;
}
case REAL: {
case REAL:
{
doubleValue = BinaryPropertyListParser.ParseDouble(bytes);
longValue = (long)Math.Round(doubleValue);
break;
}
default: {
default:
{
throw new ArgumentException("Type argument is not valid.");
}
}
@@ -94,27 +99,38 @@ namespace Claunia.PropertyList
/// <seealso cref="bool.Parse"/>
/// <seealso cref="long.Parse"/>
/// <seealso cref="double.Parse"/>
public NSNumber(string text) {
public NSNumber(string text)
{
if (text == null)
throw new ArgumentException("The given string is null and cannot be parsed as number.");
try {
try
{
long l = long.Parse(text);
doubleValue = longValue = l;
type = INTEGER;
} catch (Exception ex) {
try {
}
catch (Exception ex)
{
try
{
doubleValue = double.Parse(text, CultureInfo.InvariantCulture);
longValue = (long)Math.Round(doubleValue);
type = REAL;
} catch (Exception ex2) {
try {
}
catch (Exception ex2)
{
try
{
boolValue = text.ToLower().Equals("true") || text.ToLower().Equals("yes");
if(!boolValue && !(text.ToLower().Equals("false") || text.ToLower().Equals("no"))) {
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 ex3) {
}
catch (Exception ex3)
{
throw new ArgumentException("The given string neither represents a double, an int nor a bool value.");
}
}
@@ -125,7 +141,8 @@ namespace Claunia.PropertyList
/// Creates an integer number.
/// </summary>
/// <param name="i">The integer value.</param>
public NSNumber(int i) {
public NSNumber(int i)
{
doubleValue = longValue = i;
type = INTEGER;
}
@@ -134,7 +151,8 @@ namespace Claunia.PropertyList
/// Creates an integer number.
/// </summary>
/// <param name="l">The long integer value.</param>
public NSNumber(long l) {
public NSNumber(long l)
{
doubleValue = longValue = l;
type = INTEGER;
}
@@ -143,8 +161,9 @@ namespace Claunia.PropertyList
/// Creates a real number.
/// </summary>
/// <param name="d">The real value.</param>
public NSNumber(double d) {
longValue = (long) (doubleValue = d);
public NSNumber(double d)
{
longValue = (long)(doubleValue = d);
type = REAL;
}
@@ -152,7 +171,8 @@ namespace Claunia.PropertyList
/// Creates a bool number.
/// </summary>
/// <param name="b">The bool value.</param>
public NSNumber(bool b) {
public NSNumber(bool b)
{
boolValue = b;
doubleValue = longValue = b ? 1 : 0;
type = BOOLEAN;
@@ -165,7 +185,8 @@ namespace Claunia.PropertyList
/// <seealso cref="BOOLEAN"/>
/// <seealso cref="INTEGER"/>
/// <seealso cref="REAL"/>
public int GetNSNumberType() {
public int GetNSNumberType()
{
return type;
}
@@ -173,7 +194,8 @@ namespace Claunia.PropertyList
/// Checks whether the value of this NSNumber is a bool.
/// </summary>
/// <returns>Whether the number's value is a bool.</returns>
public bool isBoolean() {
public bool isBoolean()
{
return type == BOOLEAN;
}
@@ -181,7 +203,8 @@ namespace Claunia.PropertyList
/// Checks whether the value of this NSNumber is an integer.
/// </summary>
/// <returns>Whether the number's value is an integer.</returns>
public bool isInteger() {
public bool isInteger()
{
return type == INTEGER;
}
@@ -189,7 +212,8 @@ namespace Claunia.PropertyList
/// Checks whether the value of this NSNumber is a real number.
/// </summary>
/// <returns>Whether the number's value is a real number.</returns>
public bool isReal() {
public bool isReal()
{
return type == REAL;
}
@@ -197,7 +221,8 @@ namespace Claunia.PropertyList
/// The number's bool value.
/// </summary>
/// <returns><code>true</code> if the value is true or non-zero, <code>false</code> otherwise.</returns>
public bool ToBool() {
public bool ToBool()
{
if (type == BOOLEAN)
return boolValue;
else
@@ -208,7 +233,8 @@ namespace Claunia.PropertyList
/// The number's long value.
/// </summary>
/// <returns>The value of the number as long</returns>
public long ToLong() {
public long ToLong()
{
return longValue;
}
@@ -219,15 +245,17 @@ namespace Claunia.PropertyList
/// Otherwise the value might be innaccurate.</i>
/// </summary>
/// <returns>The value of the number as int.</returns>
public int ToInt() {
return (int) longValue;
public int ToInt()
{
return (int)longValue;
}
/// <summary>
/// The number's double value.
/// </summary>
/// <returns>The value of the number as double.</returns>
public double ToDouble() {
public double ToDouble()
{
return doubleValue;
}
@@ -236,8 +264,9 @@ namespace Claunia.PropertyList
/// WARNING: Possible loss of precision if the value is outside the float range.
/// </summary>
/// <returns>The value of the number as float.</returns>
public float floatValue() {
return (float) doubleValue;
public float floatValue()
{
return (float)doubleValue;
}
/// <summary>
@@ -245,53 +274,67 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="obj">The object to compare to.</param>
/// <returns>Whether the objects are equal in terms of numeric value and type.</returns>
public override bool Equals(Object obj) {
if (!(obj is NSNumber)) return false;
NSNumber n = (NSNumber) obj;
public override bool Equals(Object obj)
{
if (!(obj is NSNumber))
return false;
NSNumber n = (NSNumber)obj;
return type == n.type && longValue == n.longValue && doubleValue == n.doubleValue && boolValue == n.boolValue;
}
public override int GetHashCode() {
public override int GetHashCode()
{
int hash = type;
hash = 37 * hash + (int) (this.longValue ^ ((uint)this.longValue >> 32));
hash = 37 * hash + (int) (BitConverter.DoubleToInt64Bits(this.doubleValue) ^ ((uint)(BitConverter.DoubleToInt64Bits(this.doubleValue) >> 32)));
hash = 37 * hash + (int)(this.longValue ^ ((uint)this.longValue >> 32));
hash = 37 * hash + (int)(BitConverter.DoubleToInt64Bits(this.doubleValue) ^ ((uint)(BitConverter.DoubleToInt64Bits(this.doubleValue) >> 32)));
hash = 37 * hash + (ToBool() ? 1 : 0);
return hash;
}
public override string ToString() {
switch (type) {
case INTEGER: {
public override string ToString()
{
switch (type)
{
case INTEGER:
{
return ToLong().ToString();
}
case REAL: {
case REAL:
{
return ToDouble().ToString(CultureInfo.InvariantCulture);
}
case BOOLEAN: {
case BOOLEAN:
{
return ToBool().ToString();
}
default: {
default:
{
return base.ToString();
}
}
}
internal override void ToXml(StringBuilder xml, int level) {
internal override void ToXml(StringBuilder xml, int level)
{
Indent(xml, level);
switch (type) {
case INTEGER: {
switch (type)
{
case INTEGER:
{
xml.Append("<integer>");
xml.Append(ToLong());
xml.Append("</integer>");
break;
}
case REAL: {
case REAL:
{
xml.Append("<real>");
xml.Append(ToDouble().ToString(CultureInfo.InvariantCulture));
xml.Append("</real>");
break;
}
case BOOLEAN: {
case BOOLEAN:
{
if (ToBool())
xml.Append("<true/>");
else
@@ -301,67 +344,93 @@ namespace Claunia.PropertyList
}
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
switch (GetNSNumberType()) {
case INTEGER: {
if (ToLong() < 0) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
switch (GetNSNumberType())
{
case INTEGER:
{
if (ToLong() < 0)
{
outPlist.Write(0x13);
outPlist.WriteBytes(ToLong(), 8);
} else if (ToLong() <= 0xff) {
}
else if (ToLong() <= 0xff)
{
outPlist.Write(0x10);
outPlist.WriteBytes(ToLong(), 1);
} else if (ToLong() <= 0xffff) {
}
else if (ToLong() <= 0xffff)
{
outPlist.Write(0x11);
outPlist.WriteBytes(ToLong(), 2);
} else if (ToLong() <= 0xffffffffL) {
}
else if (ToLong() <= 0xffffffffL)
{
outPlist.Write(0x12);
outPlist.WriteBytes(ToLong(), 4);
} else {
}
else
{
outPlist.Write(0x13);
outPlist.WriteBytes(ToLong(), 8);
}
break;
}
case REAL: {
case REAL:
{
outPlist.Write(0x23);
outPlist.WriteDouble(ToDouble());
break;
}
case BOOLEAN: {
case BOOLEAN:
{
outPlist.Write(ToBool() ? 0x09 : 0x08);
break;
}
}
}
internal override void ToASCII(StringBuilder ascii, int level) {
internal override void ToASCII(StringBuilder ascii, int level)
{
Indent(ascii, level);
if (type == BOOLEAN) {
if (type == BOOLEAN)
{
ascii.Append(boolValue ? "YES" : "NO");
} else {
}
else
{
ascii.Append(ToString());
}
}
internal override void ToASCIIGnuStep(StringBuilder ascii, int level) {
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
{
Indent(ascii, level);
switch (type) {
case INTEGER: {
switch (type)
{
case INTEGER:
{
ascii.Append("<*I");
ascii.Append(ToString());
ascii.Append(">");
break;
}
case REAL: {
case REAL:
{
ascii.Append("<*R");
ascii.Append(ToString());
ascii.Append(">");
break;
}
case BOOLEAN: {
if (boolValue) {
case BOOLEAN:
{
if (boolValue)
{
ascii.Append("<*BY>");
} else {
}
else
{
ascii.Append("<*BN>");
}
break;
@@ -369,17 +438,23 @@ namespace Claunia.PropertyList
}
}
public int CompareTo(Object o) {
public int CompareTo(Object o)
{
double x = ToDouble();
double y;
if (o is NSNumber) {
NSNumber num = (NSNumber) o;
if (o is NSNumber)
{
NSNumber num = (NSNumber)o;
y = num.ToDouble();
return (x < y) ? -1 : ((x == y) ? 0 : 1);
} else if (IsNumber(o)) {
}
else if (IsNumber(o))
{
y = GetDoubleFromObject(o);
return (x < y) ? -1 : ((x == y) ? 0 : 1);
} else {
}
else
{
return -1;
}
}

View File

@@ -71,7 +71,8 @@ namespace Claunia.PropertyList
/// Assigns IDs to all the objects in this NSObject subtree.
/// </summary>
/// <param name="out">The writer object that handles the binary serialization.</param>
internal virtual void AssignIDs(BinaryPropertyListWriter outPlist) {
internal virtual void AssignIDs(BinaryPropertyListWriter outPlist)
{
outPlist.AssignID(this);
}
@@ -85,7 +86,8 @@ namespace Claunia.PropertyList
/// Generates a valid XML property list including headers using this object as root.
/// </summary>
/// <returns>The XML representation of the property list including XML header and doctype information.</returns>
public string ToXmlPropertyList() {
public string ToXmlPropertyList()
{
StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
xml.Append(NSObject.NEWLINE);
xml.Append("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
@@ -122,7 +124,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="xml">The string builder for the XML document.</param>
/// <param name="level">The level of identation.</param>
internal void Indent(StringBuilder xml, int level) {
internal void Indent(StringBuilder xml, int level)
{
for (int i = 0; i < level; i++)
xml.Append(INDENT);
}
@@ -132,7 +135,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="value">The value to represent as a NSObject.</param>
/// <returns>A NSObject representing the given value.</returns>
public static NSNumber Wrap(long value) {
public static NSNumber Wrap(long value)
{
return new NSNumber(value);
}
@@ -141,7 +145,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="value">The value to represent as a NSObject.</param>
/// <returns>A NSObject representing the given value.</returns>
public static NSNumber Wrap(double value) {
public static NSNumber Wrap(double value)
{
return new NSNumber(value);
}
@@ -150,7 +155,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="value">The value to represent as a NSObject.</param>
/// <returns>A NSObject representing the given value.</returns>
public static NSNumber Wrap(bool value) {
public static NSNumber Wrap(bool value)
{
return new NSNumber(value);
}
@@ -159,7 +165,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="value">The value to represent as a NSObject.</param>
/// <returns>A NSObject representing the given value.</returns>
public static NSData Wrap(byte[] value) {
public static NSData Wrap(byte[] value)
{
return new NSData(value);
}
@@ -169,9 +176,11 @@ namespace Claunia.PropertyList
/// <param name="value">The value to represent as a NSObject.</param>
/// <returns>A NSObject representing the given value.</returns>
/// <exception cref="SystemException">When one of the objects contained in the array cannot be represented by a NSObject.</exception>
public static NSArray Wrap(Object[] value) {
public static NSArray Wrap(Object[] value)
{
NSArray arr = new NSArray(value.Length);
for (int i = 0; i < value.Length; i++) {
for (int i = 0; i < value.Length; i++)
{
arr.SetValue(i, Wrap(value[i]));
}
return arr;
@@ -183,7 +192,8 @@ namespace Claunia.PropertyList
/// <param name="value">The value to represent as a NSObject.</param>
/// <returns>A NSObject representing the given value.</returns>
/// <exception cref="SystemException">When one of the values contained in the map cannot be represented by a NSObject.</exception>
public static NSDictionary Wrap(Dictionary<string, Object> value) {
public static NSDictionary Wrap(Dictionary<string, Object> value)
{
NSDictionary dict = new NSDictionary();
foreach (KeyValuePair<string, Object> kvp in value)
dict.Add(kvp.Key, Wrap(kvp.Value));
@@ -196,7 +206,8 @@ namespace Claunia.PropertyList
/// <param name="value">The value to represent as a NSObject.</param>
/// <returns>A NSObject representing the given value.</returns>
/// <exception cref="SystemException">When one of the values contained in the map cannot be represented by a NSObject.</exception>
public static NSSet Wrap(List<Object> value) {
public static NSSet Wrap(List<Object> value)
{
NSSet set = new NSSet();
foreach (Object o in value)
set.AddObject(Wrap(o));
@@ -220,101 +231,123 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="o">The object to represent.</param>
///<returns>A NSObject equivalent to the given object.</returns>
public static NSObject Wrap(Object o) {
if(o == null)
public static NSObject Wrap(Object o)
{
if (o == null)
throw new NullReferenceException("A null object cannot be wrapped as a NSObject");
if(o is NSObject)
if (o is NSObject)
return (NSObject)o;
Type c = o.GetType();
if (typeof(bool).Equals(c)) {
if (typeof(bool).Equals(c))
{
return Wrap((bool)o);
}
if (typeof(Byte).Equals(c)) {
return Wrap((int) (Byte) o);
if (typeof(Byte).Equals(c))
{
return Wrap((int)(Byte)o);
}
if (typeof(short).Equals(c)) {
return Wrap((int) (short) o);
if (typeof(short).Equals(c))
{
return Wrap((int)(short)o);
}
if (typeof(int).Equals(c)) {
return Wrap((int) (int) o);
if (typeof(int).Equals(c))
{
return Wrap((int)(int)o);
}
if (typeof(long).IsAssignableFrom(c)) {
return Wrap((long) (long) o);
if (typeof(long).IsAssignableFrom(c))
{
return Wrap((long)(long)o);
}
if (typeof(float).Equals(c)) {
return Wrap((double) (float) o);
if (typeof(float).Equals(c))
{
return Wrap((double)(float)o);
}
if (typeof(double).IsAssignableFrom(c)) {
return Wrap((double) (Double) o);
if (typeof(double).IsAssignableFrom(c))
{
return Wrap((double)(Double)o);
}
if (typeof(string).Equals(c)) {
if (typeof(string).Equals(c))
{
return new NSString((string)o);
}
if (typeof(DateTime).Equals(c)) {
if (typeof(DateTime).Equals(c))
{
return new NSDate((DateTime)o);
}
if(c.IsArray) {
if (c.IsArray)
{
Type cc = c.GetElementType();
if (cc.Equals(typeof(byte))) {
return Wrap((byte[]) o);
if (cc.Equals(typeof(byte)))
{
return Wrap((byte[])o);
}
else if(cc.Equals(typeof(bool))) {
else if (cc.Equals(typeof(bool)))
{
bool[] array = (bool[])o;
NSArray nsa = new NSArray(array.Length);
for(int i=0;i<array.Length;i++)
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
return nsa;
}
else if(cc.Equals(typeof(float))) {
else if (cc.Equals(typeof(float)))
{
float[] array = (float[])o;
NSArray nsa = new NSArray(array.Length);
for(int i=0;i<array.Length;i++)
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
return nsa;
}
else if(cc.Equals(typeof(double))) {
else if (cc.Equals(typeof(double)))
{
double[] array = (double[])o;
NSArray nsa = new NSArray(array.Length);
for(int i=0;i<array.Length;i++)
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
return nsa;
}
else if(cc.Equals(typeof(short))) {
else if (cc.Equals(typeof(short)))
{
short[] array = (short[])o;
NSArray nsa = new NSArray(array.Length);
for(int i=0;i<array.Length;i++)
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
return nsa;
}
else if(cc.Equals(typeof(int))) {
else if (cc.Equals(typeof(int)))
{
int[] array = (int[])o;
NSArray nsa = new NSArray(array.Length);
for(int i=0;i<array.Length;i++)
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
return nsa;
}
else if(cc.Equals(typeof(long))) {
else if (cc.Equals(typeof(long)))
{
long[] array = (long[])o;
NSArray nsa = new NSArray(array.Length);
for(int i=0;i<array.Length;i++)
for (int i = 0; i < array.Length; i++)
nsa.SetValue(i, Wrap(array[i]));
return nsa;
}
else {
return Wrap((Object[]) o);
else
{
return Wrap((Object[])o);
}
}
if (typeof(Dictionary<string,Object>).IsAssignableFrom(c)) {
if (typeof(Dictionary<string,Object>).IsAssignableFrom(c))
{
Dictionary<string,Object> netDict = (Dictionary<string,Object>)o;
NSDictionary dict = new NSDictionary();
foreach(KeyValuePair<string, Object> kvp in netDict) {
foreach (KeyValuePair<string, Object> kvp in netDict)
{
dict.Add(kvp.Key, Wrap(kvp.Value));
}
return dict;
}
if (typeof(List<Object>).IsAssignableFrom(c)) {
if (typeof(List<Object>).IsAssignableFrom(c))
{
return Wrap(((List<Object>)o).ToArray());
}
return WrapSerialized(o);
@@ -327,15 +360,19 @@ namespace Claunia.PropertyList
/// <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 {
public static NSData WrapSerialized(Object o)
{
try
{
BinaryFormatter bf = new BinaryFormatter();
using(MemoryStream ms = new MemoryStream())
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, o);
return new NSData(ms.ToArray());
}
} catch (IOException ex) {
}
catch (IOException ex)
{
throw new SystemException("The given object of class " + o.GetType() + " could not be serialized and stored in a NSData object.");
}
}
@@ -355,58 +392,87 @@ namespace Claunia.PropertyList
/// </ul>
/// </summary>
/// <returns>A native .NET object representing this NSObject's value.</returns>
public Object ToObject() {
if(this is NSArray) {
public Object ToObject()
{
if (this is NSArray)
{
NSObject[] arrayA = ((NSArray)this).GetArray();
Object[] arrayB = new Object[arrayA.Length];
for(int i = 0; i < arrayA.Length; i++) {
for (int i = 0; i < arrayA.Length; i++)
{
arrayB[i] = arrayA[i].ToObject();
}
return arrayB;
} else if (this is NSDictionary) {
}
else if (this is NSDictionary)
{
Dictionary<string, NSObject> dictA = ((NSDictionary)this).GetDictionary();
Dictionary<string, Object> dictB = new Dictionary<string, Object>(dictA.Count);
foreach(KeyValuePair<string, NSObject> kvp in dictA) {
foreach (KeyValuePair<string, NSObject> kvp in dictA)
{
dictB.Add(kvp.Key, kvp.Value.ToObject());
}
return dictB;
} else if(this is NSSet) {
}
else if (this is NSSet)
{
List<NSObject> setA = ((NSSet)this).GetSet();
List<Object> setB = new List<Object>();
foreach(NSObject o in setA) {
foreach (NSObject o in setA)
{
setB.Add(o.ToObject());
}
return setB;
} else if(this is NSNumber) {
}
else if (this is NSNumber)
{
NSNumber num = (NSNumber)this;
switch(num.GetNSNumberType()) {
case NSNumber.INTEGER : {
switch (num.GetNSNumberType())
{
case NSNumber.INTEGER:
{
long longVal = num.ToLong();
if(longVal > int.MaxValue || longVal < int.MinValue) {
if (longVal > int.MaxValue || longVal < int.MinValue)
{
return longVal;
} else {
}
else
{
return num.ToInt();
}
}
case NSNumber.REAL : {
case NSNumber.REAL:
{
return num.ToDouble();
}
case NSNumber.BOOLEAN : {
case NSNumber.BOOLEAN:
{
return num.ToBool();
}
default : {
default :
{
return num.ToDouble();
}
}
} else if(this is NSString) {
}
else if (this is NSString)
{
return ((NSString)this).GetContent();
} else if(this is NSData) {
}
else if (this is NSData)
{
return ((NSData)this).Bytes;
} else if(this is NSDate) {
}
else if (this is NSDate)
{
return ((NSDate)this).Date;
} else if(this is UID) {
}
else if (this is UID)
{
return ((UID)this).Bytes;
} else {
}
else
{
return this;
}
}

View File

@@ -46,7 +46,8 @@ namespace Claunia.PropertyList
/// <summary>
/// Creates an empty unordered set.
/// </summary>
public NSSet() {
public NSSet()
{
set = new List<NSObject>();
}
@@ -67,7 +68,8 @@ namespace Claunia.PropertyList
set = new TreeSet<NSObject>();
}*/
public NSSet(bool ordered) {
public NSSet(bool ordered)
{
this.ordered = ordered;
set = new List<NSObject>();
}
@@ -77,7 +79,8 @@ namespace Claunia.PropertyList
/// Create a set and fill it with the given objects.
/// </summary>
/// <param name="objects">The objects to populate the set.</param>
public NSSet(params NSObject[] objects) {
public NSSet(params NSObject[] objects)
{
set = new List<NSObject>(objects);
}
@@ -99,7 +102,8 @@ namespace Claunia.PropertyList
set.addAll(Arrays.asList(objects));
}*/
public NSSet(bool ordered, params NSObject[] objects) {
public NSSet(bool ordered, params NSObject[] objects)
{
this.ordered = ordered;
set = new List<NSObject>(objects);
if (ordered)
@@ -111,7 +115,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="obj">The object to add.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
public void AddObject(NSObject obj) {
public void AddObject(NSObject obj)
{
set.Add(obj);
if (ordered)
set.Sort();
@@ -122,7 +127,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="obj">The object to remove.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
public void RemoveObject(NSObject obj) {
public void RemoveObject(NSObject obj)
{
set.Remove(obj);
if (ordered)
set.Sort();
@@ -133,7 +139,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>An array of all objects in the set.</returns>
[MethodImpl(MethodImplOptions.Synchronized)]
public NSObject[] AllObjects() {
public NSObject[] AllObjects()
{
return set.ToArray();
}
@@ -143,7 +150,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The first object in the set, or <code>null</code> if the set is empty.</returns>
[MethodImpl(MethodImplOptions.Synchronized)]
public NSObject AnyObject() {
public NSObject AnyObject()
{
if (set.Count == 0)
return null;
else
@@ -155,7 +163,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns><c>true</c>, when the object was found, <c>false</c> otherwise.</returns>
/// <param name="obj">The object to look for.</param>
public bool ContainsObject(NSObject obj) {
public bool ContainsObject(NSObject obj)
{
return set.Contains(obj);
}
@@ -166,8 +175,10 @@ namespace Claunia.PropertyList
/// <param name="obj">The object to look for.</param>
/// <returns>The object if it is present, <code>null</code> otherwise.</returns>
[MethodImpl(MethodImplOptions.Synchronized)]
public NSObject Member(NSObject obj) {
foreach (NSObject o in set) {
public NSObject Member(NSObject obj)
{
foreach (NSObject o in set)
{
if (o.Equals(obj))
return o;
}
@@ -180,8 +191,10 @@ namespace Claunia.PropertyList
/// <returns><c>true</c> if the intersection of both sets is empty, <c>false</c> otherwise.</returns>
/// <param name="otherSet">The other set.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
public bool IntersectsSet(NSSet otherSet) {
foreach (NSObject o in set) {
public bool IntersectsSet(NSSet otherSet)
{
foreach (NSObject o in set)
{
if (otherSet.ContainsObject(o))
return true;
}
@@ -194,8 +207,10 @@ namespace Claunia.PropertyList
/// <returns><c>true</c> if all elements in this set are also present in the other set, <c>false</c>otherwise.</returns>
/// <param name="otherSet">The other set.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
public bool IsSubsetOfSet(NSSet otherSet) {
foreach (NSObject o in set) {
public bool IsSubsetOfSet(NSSet otherSet)
{
foreach (NSObject o in set)
{
if (!otherSet.ContainsObject(o))
return false;
}
@@ -209,7 +224,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The iterator for the set.</returns>
[MethodImpl(MethodImplOptions.Synchronized)]
public IEnumerator GetEnumerator() {
public IEnumerator GetEnumerator()
{
return set.GetEnumerator();
}
@@ -217,24 +233,29 @@ namespace Claunia.PropertyList
/// Gets the underlying data structure in which this NSSets stores its content.
/// </summary>
/// <returns>A Set object.</returns>
internal List<NSObject> GetSet() {
internal List<NSObject> GetSet()
{
return set;
}
public override int GetHashCode() {
public override int GetHashCode()
{
int hash = 7;
hash = 29 * hash + (this.set != null ? this.set.GetHashCode() : 0);
return hash;
}
public override bool Equals(Object obj) {
if (obj == null) {
public override bool Equals(Object obj)
{
if (obj == null)
{
return false;
}
if (GetType() != obj.GetType()) {
if (GetType() != obj.GetType())
{
return false;
}
NSSet other = (NSSet) obj;
NSSet other = (NSSet)obj;
return !(this.set != other.set && (this.set == null || !this.set.Equals(other.set)));
}
@@ -260,13 +281,15 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="xml">The XML StringBuilder</param>
/// <param name="level">The indentation level</param>
internal override void ToXml(StringBuilder xml, int level) {
internal override void ToXml(StringBuilder xml, int level)
{
Indent(xml, level);
xml.Append("<array>");
xml.Append(NSObject.NEWLINE);
if (ordered)
set.Sort();
foreach (NSObject o in set) {
foreach (NSObject o in set)
{
o.ToXml(xml, level + 1);
xml.Append(NSObject.NEWLINE);
}
@@ -274,21 +297,28 @@ namespace Claunia.PropertyList
xml.Append("</array>");
}
internal override void AssignIDs(BinaryPropertyListWriter outPlist) {
internal override void AssignIDs(BinaryPropertyListWriter outPlist)
{
base.AssignIDs(outPlist);
foreach (NSObject obj in set) {
foreach (NSObject obj in set)
{
obj.AssignIDs(outPlist);
}
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
if (ordered) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
if (ordered)
{
set.Sort();
outPlist.WriteIntHeader(0xB, set.Count);
} else {
}
else
{
outPlist.WriteIntHeader(0xC, set.Count);
}
foreach (NSObject obj in set) {
foreach (NSObject obj in set)
{
outPlist.WriteID(outPlist.GetID(obj));
}
}
@@ -300,21 +330,26 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="ascii">The ASCII file string builder</param>
/// <param name="level">The indentation level</param>
internal override void ToASCII(StringBuilder ascii, int level) {
internal override void ToASCII(StringBuilder ascii, int level)
{
Indent(ascii, level);
if (ordered)
set.Sort();
NSObject[] array = AllObjects();
ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE);
for (int i = 0; i < array.Length; i++) {
for (int i = 0; i < array.Length; i++)
{
Type objClass = array[i].GetType();
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
&& indexOfLastNewLine != ascii.Length) {
&& indexOfLastNewLine != ascii.Length)
{
ascii.Append(NEWLINE);
indexOfLastNewLine = ascii.Length;
array[i].ToASCII(ascii, level + 1);
} else {
}
else
{
if (i != 0)
ascii.Append(" ");
array[i].ToASCII(ascii, 0);
@@ -323,7 +358,8 @@ namespace Claunia.PropertyList
if (i != array.Length - 1)
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) {
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
{
ascii.Append(NEWLINE);
indexOfLastNewLine = ascii.Length;
}
@@ -338,21 +374,26 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="ascii">The ASCII file string builder</param>
/// <param name="level">The indentation level</param>
internal override void ToASCIIGnuStep(StringBuilder ascii, int level) {
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
{
Indent(ascii, level);
if (ordered)
set.Sort();
NSObject[] array = AllObjects();
ascii.Append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
int indexOfLastNewLine = ascii.ToString().LastIndexOf(NEWLINE);
for (int i = 0; i < array.Length; i++) {
for (int i = 0; i < array.Length; i++)
{
Type objClass = array[i].GetType();
if ((objClass.Equals(typeof(NSDictionary)) || objClass.Equals(typeof(NSArray)) || objClass.Equals(typeof(NSData)))
&& indexOfLastNewLine != ascii.Length) {
&& indexOfLastNewLine != ascii.Length)
{
ascii.Append(NEWLINE);
indexOfLastNewLine = ascii.Length;
array[i].ToASCIIGnuStep(ascii, level + 1);
} else {
}
else
{
if (i != 0)
ascii.Append(" ");
array[i].ToASCIIGnuStep(ascii, 0);
@@ -361,7 +402,8 @@ namespace Claunia.PropertyList
if (i != array.Length - 1)
ascii.Append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH) {
if (ascii.Length - indexOfLastNewLine > ASCII_LINE_LENGTH)
{
ascii.Append(NEWLINE);
indexOfLastNewLine = ascii.Length;
}

View File

@@ -42,7 +42,8 @@ namespace Claunia.PropertyList
/// <param name="bytes">The binary representation.</param>
/// <param name="encoding">The encoding of the binary representation, the name of a supported charset.</param>
/// <exception cref="ArgumentException">The encoding charset is invalid or not supported by the underlying platform.</exception>
public NSString(byte[] bytes, String encoding) {
public NSString(byte[] bytes, String encoding)
{
Encoding enc = Encoding.GetEncoding(encoding);
content = enc.GetString(bytes);
}
@@ -51,7 +52,8 @@ namespace Claunia.PropertyList
/// Creates a NSString from a string.
/// </summary>
/// <param name="string">The string that will be contained in the NSString.</param>
public NSString(string text) {
public NSString(string text)
{
content = text;
}
@@ -59,7 +61,8 @@ namespace Claunia.PropertyList
/// Gets this strings content.
/// </summary>
/// <returns>This NSString as .NET string object.</returns>
public string GetContent() {
public string GetContent()
{
return content;
}
@@ -67,7 +70,8 @@ namespace Claunia.PropertyList
/// Sets the contents of this string.
/// </summary>
/// <param name="c">The new content of this string object.</param>
public void SetContent(string c) {
public void SetContent(string c)
{
content = c;
}
@@ -75,7 +79,8 @@ namespace Claunia.PropertyList
/// Appends a string to this string.
/// </summary>
/// <param name="s">The string to append.</param>
public void Append(NSString s) {
public void Append(NSString s)
{
Append(s.GetContent());
}
@@ -83,7 +88,8 @@ namespace Claunia.PropertyList
/// Appends a string to this string.
/// </summary>
/// <param name="s">The string to append.</param>
public void Append(string s) {
public void Append(string s)
{
content += s;
}
@@ -91,7 +97,8 @@ namespace Claunia.PropertyList
/// Prepends a string to this string.
/// </summary>
/// <param name="s">The string to prepend.</param>
public void Prepend(string s) {
public void Prepend(string s)
{
content = s + content;
}
@@ -99,16 +106,20 @@ namespace Claunia.PropertyList
/// Prepends a string to this string.
/// </summary>
/// <param name="s">The string to prepend.</param>
public void Prepend(NSString s) {
public void Prepend(NSString s)
{
Prepend(s.GetContent());
}
public override bool Equals(Object obj) {
if (!(obj is NSString)) return false;
return content.Equals(((NSString) obj).content);
public override bool Equals(Object obj)
{
if (!(obj is NSString))
return false;
return content.Equals(((NSString)obj).content);
}
public override int GetHashCode() {
public override int GetHashCode()
{
return content.GetHashCode();
}
@@ -116,13 +127,15 @@ namespace Claunia.PropertyList
/// The textual representation of this NSString.
/// </summary>
/// <returns>The NSString's contents.</returns>
public override string ToString() {
public override string ToString()
{
return content;
}
static Encoding asciiEncoder, utf16beEncoder, utf8Encoder;
internal override void ToXml(StringBuilder xml, int level) {
internal override void ToXml(StringBuilder xml, int level)
{
Indent(xml, level);
xml.Append("<string>");
@@ -132,38 +145,49 @@ namespace Claunia.PropertyList
if (utf8Encoder == null)
utf8Encoder = Encoding.GetEncoding("UTF-8");
try {
try
{
byte[] bytes = utf8Encoder.GetBytes(content);
content = utf8Encoder.GetString(bytes);
} catch (Exception ex) {
}
catch (Exception ex)
{
throw new SystemException("Could not encode the NSString into UTF-8: " + ex.Message);
}
}
//According to http://www.w3.org/TR/REC-xml/#syntax node values must not
//contain the characters < or &. Also the > character should be escaped.
if (content.Contains("&") || content.Contains("<") || content.Contains(">")) {
if (content.Contains("&") || content.Contains("<") || content.Contains(">"))
{
xml.Append("<![CDATA[");
xml.Append(content.Replace("]]>", "]]]]><![CDATA[>"));
xml.Append("]]>");
} else {
}
else
{
xml.Append(content);
}
xml.Append("</string>");
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
int kind;
byte[] byteBuf;
lock (typeof(NSString)) {
lock (typeof(NSString))
{
if (asciiEncoder == null)
// Not much use, because some characters do not fallback to exception, even if not ASCII
asciiEncoder = Encoding.GetEncoding("ascii", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
if(IsASCIIEncodable(content)) {
if (IsASCIIEncodable(content))
{
kind = 0x5; // standard ASCII
byteBuf = asciiEncoder.GetBytes(content);
} else {
}
else
{
if (utf16beEncoder == null)
utf16beEncoder = Encoding.BigEndianUnicode;
@@ -175,7 +199,8 @@ namespace Claunia.PropertyList
outPlist.Write(byteBuf);
}
internal override void ToASCII(StringBuilder ascii, int level) {
internal override void ToASCII(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append("\"");
//According to https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
@@ -186,7 +211,8 @@ namespace Claunia.PropertyList
ascii.Append("\"");
}
internal override void ToASCIIGnuStep(StringBuilder ascii, int level) {
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append("\"");
ascii.Append(EscapeStringForASCII(content));
@@ -198,50 +224,73 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The unescaped string.</returns>
/// <param name="s">S.</param>
internal static string EscapeStringForASCII(string s) {
internal static string EscapeStringForASCII(string s)
{
string outString = "";
char[] cArray = s.ToCharArray();
for (int i = 0; i < cArray.Length; i++) {
for (int i = 0; i < cArray.Length; i++)
{
char c = cArray[i];
if (c > 127) {
if (c > 127)
{
//non-ASCII Unicode
outString += "\\U";
string hex = String.Format("{0:x}", c);
while (hex.Length < 4)
hex = "0" + hex;
outString += hex;
} else if (c == '\\') {
}
else if (c == '\\')
{
outString += "\\\\";
} else if (c == '\"') {
}
else if (c == '\"')
{
outString += "\\\"";
} else if (c == '\b') {
}
else if (c == '\b')
{
outString += "\\b";
} else if (c == '\n') {
}
else if (c == '\n')
{
outString += "\\n";
} else if (c == '\r') {
}
else if (c == '\r')
{
outString += "\\r";
} else if (c == '\t') {
}
else if (c == '\t')
{
outString += "\\t";
} else {
}
else
{
outString += c;
}
}
return outString;
}
public int CompareTo(Object o) {
if (o is NSString) {
return GetContent().CompareTo(((NSString) o).GetContent());
} else if (o is String) {
return GetContent().CompareTo(((String) o));
} else {
public int CompareTo(Object o)
{
if (o is NSString)
{
return GetContent().CompareTo(((NSString)o).GetContent());
}
else if (o is String)
{
return GetContent().CompareTo(((String)o));
}
else
{
return -1;
}
}
public override bool Equals(NSObject obj)
{
if(!(obj is NSString))
if (!(obj is NSString))
return false;
return content == ((NSString)obj).content;
@@ -249,8 +298,8 @@ namespace Claunia.PropertyList
internal static bool IsASCIIEncodable(string text)
{
foreach(char c in text)
if((int)c > 0x7F)
foreach (char c in text)
if ((int)c > 0x7F)
return false;
return true;
}

View File

@@ -38,7 +38,7 @@ namespace Claunia.PropertyList
/// Creates a new exception with the given message.
/// </summary>
/// <param name="message">A message containing information about the nature of the exception.</param>
public PropertyListFormatException(string message) : base (message)
public PropertyListFormatException(string message) : base(message)
{
}
}

View File

@@ -49,18 +49,23 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The type of the property list</returns>
/// <param name="dataBeginning">The very first bytes of data of the property list (minus any whitespace) as a string</param>
private static int DetermineType(string dataBeginning) {
private static int DetermineType(string dataBeginning)
{
dataBeginning = dataBeginning.Trim();
if(dataBeginning.Length == 0) {
if (dataBeginning.Length == 0)
{
return TYPE_ERROR_BLANK;
}
if(dataBeginning.StartsWith("bplist")) {
if (dataBeginning.StartsWith("bplist"))
{
return TYPE_BINARY;
}
if(dataBeginning.StartsWith("(") || dataBeginning.StartsWith("{") || dataBeginning.StartsWith("/")) {
if (dataBeginning.StartsWith("(") || dataBeginning.StartsWith("{") || dataBeginning.StartsWith("/"))
{
return TYPE_ASCII;
}
if(dataBeginning.StartsWith("<")) {
if (dataBeginning.StartsWith("<"))
{
return TYPE_XML;
}
return TYPE_ERROR_UNKNOWN;
@@ -71,10 +76,12 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The very first bytes of data of the property list (minus any whitespace)</returns>
/// <param name="bytes">The type of the property list</param>
private static int DetermineType(byte[] bytes) {
private static int DetermineType(byte[] bytes)
{
//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') {
while (offset < bytes.Length && bytes[offset] == ' ' || bytes[offset] == '\t' || bytes[offset] == '\r' || bytes[offset] == '\n' || bytes[offset] == '\f')
{
offset++;
}
return DetermineType(Encoding.ASCII.GetString(bytes, offset, Math.Min(8, bytes.Length - offset)));
@@ -87,12 +94,14 @@ 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>
private static int DetermineType(Stream fs) {
private static int DetermineType(Stream fs)
{
//Skip any possible whitespace at the beginning of the file
byte[] magicBytes = new byte[8];
int b;
long mark;
do {
do
{
mark = fs.Position;
b = fs.ReadByte();
}
@@ -107,7 +116,7 @@ namespace Claunia.PropertyList
int type = DetermineType(Encoding.ASCII.GetString(magicBytes, 0, read));
fs.Seek(mark, SeekOrigin.Begin);
//if(fs.markSupported())
// fs.reset();
// fs.reset();
return type;
}
@@ -116,13 +125,15 @@ namespace Claunia.PropertyList
/// a maximum count.
/// </summary>
/// <param name="fs">The Stream pointing to the data that should be stored in the array.</param>
internal static byte[] ReadAll(Stream fs) {
internal static byte[] ReadAll(Stream fs)
{
MemoryStream outputStream = new MemoryStream();
byte[] buf = new byte[512];
int read = 512;
while (read == 512) {
while (read == 512)
{
read = fs.Read(buf, 0, 512);
if(read != -1)
if (read != -1)
outputStream.Write(buf, 0, read);
}
return outputStream.ToArray();
@@ -133,7 +144,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="filePath">Path to the property list file.</param>
/// <returns>The root object in the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(string filePath) {
public static NSObject Parse(string filePath)
{
return Parse(new FileInfo(filePath));
}
@@ -142,11 +154,13 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="f">The property list file.</param>
/// <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) {
public static NSObject Parse(FileInfo f)
{
FileStream fis = f.OpenRead();
int type = DetermineType(fis);
fis.Close();
switch(type) {
switch (type)
{
case TYPE_BINARY:
return BinaryPropertyListParser.Parse(f);
case TYPE_XML:
@@ -163,8 +177,10 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="bytes">The property list data as a byte array.</param>
/// <returns>The root object in the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(byte[] bytes) {
switch(DetermineType(bytes)) {
public static NSObject Parse(byte[] bytes)
{
switch (DetermineType(bytes))
{
case TYPE_BINARY:
return BinaryPropertyListParser.Parse(bytes);
case TYPE_XML:
@@ -181,7 +197,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="fs">The Stream delivering the property list data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(Stream fs) {
public static NSObject Parse(Stream fs)
{
return Parse(ReadAll(fs));
}
@@ -191,7 +208,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outFile">The output file.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsXml(NSObject root, FileInfo outFile) {
public static void SaveAsXml(NSObject root, FileInfo outFile)
{
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
@@ -206,7 +224,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outStream">The output stream.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsXml(NSObject root, Stream outStream) {
public static void SaveAsXml(NSObject root, Stream outStream)
{
StreamWriter w = new StreamWriter(outStream, Encoding.UTF8);
w.Write(root.ToXmlPropertyList());
w.Close();
@@ -217,7 +236,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="inFile">The source file.</param>
/// <param name="outFile">The target file.</param>
public static void ConvertToXml(FileInfo inFile, FileInfo outFile) {
public static void ConvertToXml(FileInfo inFile, FileInfo outFile)
{
NSObject root = Parse(inFile);
SaveAsXml(root, outFile);
}
@@ -228,7 +248,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outFile"></param>The output file.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsBinary(NSObject root, FileInfo outFile) {
public static void SaveAsBinary(NSObject root, FileInfo outFile)
{
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
@@ -241,7 +262,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outStream">The output stream.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsBinary(NSObject root, Stream outStream) {
public static void SaveAsBinary(NSObject root, Stream outStream)
{
//BinaryPropertyListWriter.write(outStream, root);
}
@@ -250,7 +272,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="inFile">The source file.</param>
/// <param name="outFile">The target file.</param>
public static void ConvertToBinary(FileInfo inFile, FileInfo outFile) {
public static void ConvertToBinary(FileInfo inFile, FileInfo outFile)
{
NSObject root = Parse(inFile);
SaveAsBinary(root, outFile);
}
@@ -261,7 +284,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outFile">The output file.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsASCII(NSDictionary root, FileInfo outFile) {
public static void SaveAsASCII(NSDictionary root, FileInfo outFile)
{
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
@@ -278,7 +302,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outFile">The output file.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsASCII(NSArray root, FileInfo outFile) {
public static void SaveAsASCII(NSArray root, FileInfo outFile)
{
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
@@ -294,17 +319,21 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="inFile">The source file.</param>
/// <param name="outFile">The target file.</param>
public static void ConvertToASCII(FileInfo inFile, FileInfo outFile) {
public static void ConvertToASCII(FileInfo inFile, FileInfo outFile)
{
NSObject root = Parse(inFile);
if(root is NSDictionary) {
SaveAsASCII((NSDictionary) root, outFile);
if (root is NSDictionary)
{
SaveAsASCII((NSDictionary)root, outFile);
}
else if(root is NSArray) {
SaveAsASCII((NSArray) root, outFile);
else if (root is NSArray)
{
SaveAsASCII((NSArray)root, outFile);
}
else {
else
{
throw new PropertyListFormatException("The root of the given input property list "
+ "is neither a Dictionary nor an Array!");
+ "is neither a Dictionary nor an Array!");
}
}
@@ -314,7 +343,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outFile">The output file.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsGnuStepASCII(NSDictionary root, FileInfo outFile) {
public static void SaveAsGnuStepASCII(NSDictionary root, FileInfo outFile)
{
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
@@ -331,7 +361,8 @@ namespace Claunia.PropertyList
/// <param name="root">The root object.</param>
/// <param name="outFile">The output file.</param>
/// <exception cref="IOException">When an error occurs during the writing process.</exception>
public static void SaveAsGnuStepASCII(NSArray root, FileInfo outFile) {
public static void SaveAsGnuStepASCII(NSArray root, FileInfo outFile)
{
string parent = outFile.DirectoryName;
if (!Directory.Exists(parent))
Directory.CreateDirectory(parent);
@@ -347,17 +378,21 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="inFile">The source file.</param>
/// <param name="outFile">The target file.</param>
public static void ConvertToGnuStepASCII(FileInfo inFile, FileInfo outFile) {
public static void ConvertToGnuStepASCII(FileInfo inFile, FileInfo outFile)
{
NSObject root = Parse(inFile);
if(root is NSDictionary) {
SaveAsGnuStepASCII((NSDictionary) root, outFile);
if (root is NSDictionary)
{
SaveAsGnuStepASCII((NSDictionary)root, outFile);
}
else if(root is NSArray) {
SaveAsGnuStepASCII((NSArray) root, outFile);
else if (root is NSArray)
{
SaveAsGnuStepASCII((NSArray)root, outFile);
}
else {
else
{
throw new PropertyListFormatException("The root of the given input property list "
+ "is neither a Dictionary nor an Array!");
+ "is neither a Dictionary nor an Array!");
}
}
}

View File

@@ -65,32 +65,38 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="xml">The xml StringBuilder</param>
/// <param name="level">The indentation level</param>
internal override void ToXml(StringBuilder xml, int level) {
internal override void ToXml(StringBuilder xml, int level)
{
Indent(xml, level);
xml.Append("<string>");
for (int i = 0; i < bytes.Length; i++) {
for (int i = 0; i < bytes.Length; i++)
{
byte b = bytes[i];
xml.Append(String.Format("{0:x2}", b));
}
xml.Append("</string>");
}
internal override void ToBinary(BinaryPropertyListWriter outPlist) {
internal override void ToBinary(BinaryPropertyListWriter outPlist)
{
outPlist.Write(0x80 + bytes.Length - 1);
outPlist.Write(bytes);
}
internal override void ToASCII(StringBuilder ascii, int level) {
internal override void ToASCII(StringBuilder ascii, int level)
{
Indent(ascii, level);
ascii.Append("\"");
for (int i = 0; i < bytes.Length; i++) {
for (int i = 0; i < bytes.Length; i++)
{
byte b = bytes[i];
ascii.Append(String.Format("{0:x2}", b));
}
ascii.Append("\"");
}
internal override void ToASCIIGnuStep(StringBuilder ascii, int level) {
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
{
ToASCII(ascii, level);
}

View File

@@ -41,7 +41,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="f">The XML property list file.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(FileInfo f) {
public static NSObject Parse(FileInfo f)
{
XmlDocument doc = new XmlDocument();
doc.Load(f.OpenRead());
@@ -53,7 +54,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="bytes">The byte array containing the property list's data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(byte[] bytes) {
public static NSObject Parse(byte[] bytes)
{
MemoryStream bis = new MemoryStream(bytes);
return Parse(bis);
}
@@ -63,7 +65,8 @@ namespace Claunia.PropertyList
/// </summary>
/// <param name="str">The input stream pointing to the property list's data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(Stream str) {
public static NSObject Parse(Stream str)
{
XmlDocument doc = new XmlDocument();
doc.Load(str);
@@ -75,29 +78,42 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The root NSObject of the property list contained in the XML document.</returns>
/// <param name="doc">The XML document.</param>
private static NSObject ParseDocument(XmlDocument doc) {
private static NSObject ParseDocument(XmlDocument doc)
{
XmlDocumentType docType = doc.DocumentType;
if (docType == null) {
if (!doc.DocumentElement.Name.Equals("plist")) {
if (docType == null)
{
if (!doc.DocumentElement.Name.Equals("plist"))
{
throw new XmlException("The given XML document is not a property list.");
}
} else if (!docType.Name.Equals("plist")) {
}
else if (!docType.Name.Equals("plist"))
{
throw new XmlException("The given XML document is not a property list.");
}
XmlNode rootNode;
if (doc.DocumentElement.Name.Equals("plist")) {
if (doc.DocumentElement.Name.Equals("plist"))
{
//Root element wrapped in plist tag
List<XmlNode> rootNodes = FilterElementNodes(doc.DocumentElement.ChildNodes);
if (rootNodes.Count == 0) {
if (rootNodes.Count == 0)
{
throw new PropertyListFormatException("The given XML property list has no root element!");
} else if (rootNodes.Count == 1) {
}
else if (rootNodes.Count == 1)
{
rootNode = rootNodes[0];
} else {
}
else
{
throw new PropertyListFormatException("The given XML property list has more than one root element!");
}
} else {
}
else
{
//Root NSObject not wrapped in plist-tag
rootNode = doc.DocumentElement;
}
@@ -110,11 +126,14 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The corresponding NSObject.</returns>
/// <param name="n">The XML node.</param>
private static NSObject ParseObject(XmlNode n) {
if (n.Name.Equals("dict")) {
private static NSObject ParseObject(XmlNode n)
{
if (n.Name.Equals("dict"))
{
NSDictionary dict = new NSDictionary();
List<XmlNode> children = FilterElementNodes(n.ChildNodes);
for (int i = 0; i < children.Count; i += 2) {
for (int i = 0; i < children.Count; i += 2)
{
XmlNode key = children[i];
XmlNode val = children[i + 1];
@@ -123,26 +142,43 @@ namespace Claunia.PropertyList
dict.Add(keyString, ParseObject(val));
}
return dict;
} else if (n.Name.Equals("array")) {
}
else if (n.Name.Equals("array"))
{
List<XmlNode> children = FilterElementNodes(n.ChildNodes);
NSArray array = new NSArray(children.Count);
for (int i = 0; i < children.Count; i++) {
for (int i = 0; i < children.Count; i++)
{
array.SetValue(i, ParseObject(children[i]));
}
return array;
} else if (n.Name.Equals("true")) {
}
else if (n.Name.Equals("true"))
{
return new NSNumber(true);
} else if (n.Name.Equals("false")) {
}
else if (n.Name.Equals("false"))
{
return new NSNumber(false);
} else if (n.Name.Equals("integer")) {
}
else if (n.Name.Equals("integer"))
{
return new NSNumber(GetNodeTextContents(n));
} else if (n.Name.Equals("real")) {
}
else if (n.Name.Equals("real"))
{
return new NSNumber(GetNodeTextContents(n));
} else if (n.Name.Equals("string")) {
}
else if (n.Name.Equals("string"))
{
return new NSString(GetNodeTextContents(n));
} else if (n.Name.Equals("data")) {
}
else if (n.Name.Equals("data"))
{
return new NSData(GetNodeTextContents(n));
} else if (n.Name.Equals("date")) {
}
else if (n.Name.Equals("date"))
{
return new NSDate(GetNodeTextContents(n));
}
return null;
@@ -153,16 +189,19 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The sublist containing only nodes representing actual elements.</returns>
/// <param name="list">The list of nodes to search.</param>
private static List<XmlNode> FilterElementNodes(XmlNodeList list) {
private static List<XmlNode> FilterElementNodes(XmlNodeList list)
{
List<XmlNode> result = new List<XmlNode>();
foreach (XmlNode child in list) {
if (child.NodeType == XmlNodeType.Element) {
foreach (XmlNode child in list)
{
if (child.NodeType == XmlNodeType.Element)
{
result.Add(child);
}
}
return result;
}
/// <summary>
/// Returns a node's text content.
/// This method will return the text value represented by the node's direct children.
@@ -170,20 +209,27 @@ namespace Claunia.PropertyList
/// </summary>
/// <returns>The node's text content.</returns>
/// <param name="n">The node.</param>
private static string GetNodeTextContents(XmlNode n) {
if (n.NodeType == XmlNodeType.Text || n.NodeType == XmlNodeType.CDATA) {
private static string GetNodeTextContents(XmlNode n)
{
if (n.NodeType == XmlNodeType.Text || n.NodeType == XmlNodeType.CDATA)
{
string content = n.Value; //This concatenates any adjacent text/cdata/entity nodes
if (content == null)
return "";
else
return content;
} else {
if (n.HasChildNodes) {
}
else
{
if (n.HasChildNodes)
{
XmlNodeList children = n.ChildNodes;
foreach (XmlNode child in children) {
foreach (XmlNode child in children)
{
//Skip any non-text nodes, like comments or entities
if (child.NodeType == XmlNodeType.Text || child.NodeType == XmlNodeType.CDATA) {
if (child.NodeType == XmlNodeType.Text || child.NodeType == XmlNodeType.CDATA)
{
string content = child.Value; //This concatenates any adjacent text/cdata/entity nodes
if (content == null)
return "";
@@ -193,10 +239,14 @@ namespace Claunia.PropertyList
}
return "";
} else {
}
else
{
return "";
}
}
} }
}
}
}