mirror of
https://github.com/claunia/plist-cil.git
synced 2025-12-16 19:14:26 +00:00
Reformat code.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user