mirror of
https://github.com/claunia/plist-cil.git
synced 2025-12-16 19:14:26 +00:00
323 lines
12 KiB
C#
323 lines
12 KiB
C#
// plist-cil - An open source library to parse and generate property lists for .NET
|
|
// Copyright (C) 2015 Natalia Portillo
|
|
//
|
|
// This code is based on:
|
|
// plist - An open source library to parse and generate property lists
|
|
// Copyright (C) 2014 Daniel Dreibrodt
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
using System;
|
|
using System.Text;
|
|
|
|
namespace Claunia.PropertyList
|
|
{
|
|
/// <summary>
|
|
/// A NSString contains a string.
|
|
/// </summary>
|
|
/// @author Daniel Dreibrodt
|
|
/// @author Natalia Portillo
|
|
public class NSString : NSObject, IComparable
|
|
{
|
|
string content;
|
|
|
|
/// <summary>
|
|
/// Creates a NSString from its binary representation.
|
|
/// </summary>
|
|
/// <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)
|
|
{
|
|
Encoding enc = Encoding.GetEncoding(encoding);
|
|
content = enc.GetString(bytes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a NSString from a string.
|
|
/// </summary>
|
|
/// <param name="text">The string that will be contained in the NSString.</param>
|
|
public NSString(string text)
|
|
{
|
|
content = text;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets this strings content.
|
|
/// </summary>
|
|
/// <returns>This NSString as .NET string object.</returns>
|
|
public string GetContent()
|
|
{
|
|
return content;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the contents of this string.
|
|
/// </summary>
|
|
/// <param name="c">The new content of this string object.</param>
|
|
public void SetContent(string c)
|
|
{
|
|
content = c;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Appends a string to this string.
|
|
/// </summary>
|
|
/// <param name="s">The string to append.</param>
|
|
public void Append(NSString s)
|
|
{
|
|
Append(s.GetContent());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Appends a string to this string.
|
|
/// </summary>
|
|
/// <param name="s">The string to append.</param>
|
|
public void Append(string s)
|
|
{
|
|
content += s;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepends a string to this string.
|
|
/// </summary>
|
|
/// <param name="s">The string to prepend.</param>
|
|
public void Prepend(string s)
|
|
{
|
|
content = s + content;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepends a string to this string.
|
|
/// </summary>
|
|
/// <param name="s">The string to prepend.</param>
|
|
public void Prepend(NSString s)
|
|
{
|
|
Prepend(s.GetContent());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="Claunia.PropertyList.NSString"/>.
|
|
/// </summary>
|
|
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="Claunia.PropertyList.NSString"/>.</param>
|
|
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
|
|
/// <see cref="Claunia.PropertyList.NSString"/>; otherwise, <c>false</c>.</returns>
|
|
public override bool Equals(Object obj)
|
|
{
|
|
if (!(obj is NSString))
|
|
return false;
|
|
return content.Equals(((NSString)obj).content);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serves as a hash function for a <see cref="Claunia.PropertyList.NSString"/> object.
|
|
/// </summary>
|
|
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
|
/// hash table.</returns>
|
|
public override int GetHashCode()
|
|
{
|
|
return content.GetHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The textual representation of this NSString.
|
|
/// </summary>
|
|
/// <returns>The NSString's contents.</returns>
|
|
public override string ToString()
|
|
{
|
|
return content;
|
|
}
|
|
|
|
static Encoding asciiEncoder, utf16beEncoder, utf8Encoder;
|
|
|
|
internal override void ToXml(StringBuilder xml, int level)
|
|
{
|
|
Indent(xml, level);
|
|
xml.Append("<string>");
|
|
|
|
//Make sure that the string is encoded in UTF-8 for the XML output
|
|
lock (typeof(NSString))
|
|
{
|
|
if (utf8Encoder == null)
|
|
utf8Encoder = Encoding.GetEncoding("UTF-8");
|
|
|
|
try
|
|
{
|
|
byte[] bytes = utf8Encoder.GetBytes(content);
|
|
content = utf8Encoder.GetString(bytes);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new PropertyListException("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(">"))
|
|
{
|
|
xml.Append("<![CDATA[");
|
|
xml.Append(content.Replace("]]>", "]]]]><![CDATA[>"));
|
|
xml.Append("]]>");
|
|
}
|
|
else
|
|
{
|
|
xml.Append(content);
|
|
}
|
|
xml.Append("</string>");
|
|
}
|
|
|
|
internal override void ToBinary(BinaryPropertyListWriter outPlist)
|
|
{
|
|
int kind;
|
|
byte[] byteBuf;
|
|
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))
|
|
{
|
|
kind = 0x5; // standard ASCII
|
|
byteBuf = asciiEncoder.GetBytes(content);
|
|
}
|
|
else
|
|
{
|
|
if (utf16beEncoder == null)
|
|
utf16beEncoder = Encoding.BigEndianUnicode;
|
|
|
|
kind = 0x6; // UTF-16-BE
|
|
byteBuf = utf16beEncoder.GetBytes(content);
|
|
}
|
|
}
|
|
outPlist.WriteIntHeader(kind, content.Length);
|
|
outPlist.Write(byteBuf);
|
|
}
|
|
|
|
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
|
|
//non-ASCII characters are not escaped but simply written into the
|
|
//file, thus actually violating the ASCII plain text format.
|
|
//We will escape the string anyway because current Xcode project files (ASCII property lists) also escape their strings.
|
|
ascii.Append(EscapeStringForASCII(content));
|
|
ascii.Append("\"");
|
|
}
|
|
|
|
internal override void ToASCIIGnuStep(StringBuilder ascii, int level)
|
|
{
|
|
Indent(ascii, level);
|
|
ascii.Append("\"");
|
|
ascii.Append(EscapeStringForASCII(content));
|
|
ascii.Append("\"");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Escapes a string for use in ASCII property lists.
|
|
/// </summary>
|
|
/// <returns>The unescaped string.</returns>
|
|
/// <param name="s">S.</param>
|
|
internal static string EscapeStringForASCII(string s)
|
|
{
|
|
string outString = "";
|
|
char[] cArray = s.ToCharArray();
|
|
foreach (char c in cArray)
|
|
{
|
|
if (c > 127)
|
|
{
|
|
//non-ASCII Unicode
|
|
outString += "\\U";
|
|
string hex = String.Format("{0:x}", c);
|
|
while (hex.Length < 4)
|
|
hex = "0" + hex;
|
|
outString += hex;
|
|
}
|
|
else if (c == '\\')
|
|
{
|
|
outString += "\\\\";
|
|
}
|
|
else if (c == '\"')
|
|
{
|
|
outString += "\\\"";
|
|
}
|
|
else if (c == '\b')
|
|
{
|
|
outString += "\\b";
|
|
}
|
|
else if (c == '\n')
|
|
{
|
|
outString += "\\n";
|
|
}
|
|
else if (c == '\r')
|
|
{
|
|
outString += "\\r";
|
|
}
|
|
else if (c == '\t')
|
|
{
|
|
outString += "\\t";
|
|
}
|
|
else
|
|
{
|
|
outString += c;
|
|
}
|
|
}
|
|
return outString;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares the current <see cref="Claunia.PropertyList.NSString"/> to the specified object.
|
|
/// </summary>
|
|
/// <returns>A 32-bit signed integer that indicates the lexical relationship between the two comparands.</returns>
|
|
/// <param name="o">Object to compare to the current <see cref="Claunia.PropertyList.NSString"/>.</param>
|
|
public int CompareTo(Object o)
|
|
{
|
|
if (o is NSString)
|
|
return string.Compare(GetContent(), ((NSString)o).GetContent(), StringComparison.Ordinal);
|
|
if (o is String)
|
|
return string.Compare(GetContent(), ((String)o), StringComparison.Ordinal);
|
|
return -1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current <see cref="Claunia.PropertyList.NSString"/>.
|
|
/// </summary>
|
|
/// <param name="obj">The <see cref="Claunia.PropertyList.NSObject"/> to compare with the current <see cref="Claunia.PropertyList.NSString"/>.</param>
|
|
/// <returns><c>true</c> if the specified <see cref="Claunia.PropertyList.NSObject"/> is equal to the current
|
|
/// <see cref="Claunia.PropertyList.NSString"/>; otherwise, <c>false</c>.</returns>
|
|
public override bool Equals(NSObject obj)
|
|
{
|
|
if (!(obj is NSString))
|
|
return false;
|
|
|
|
return content == ((NSString)obj).content;
|
|
}
|
|
|
|
internal static bool IsASCIIEncodable(string text)
|
|
{
|
|
foreach (char c in text)
|
|
if ((int)c > 0x7F)
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|