mirror of
https://github.com/claunia/plist-cil.git
synced 2025-12-16 19:14:26 +00:00
Merge pull request #21 from quamotion/fixes/binary-compatibility
Binary compatibility with the Apple Plist format
This commit is contained in:
@@ -61,6 +61,21 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
public const int VERSION_20 = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether two equivalent objects should be serialized once in the binary property list file, or whether
|
||||
/// the value should be stored multiple times in the binary property list file. The default is <see langword="false"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In most scenarios, you want this to be <see langword="true"/>, as it reduces the size of the binary proeprty list file. However,
|
||||
/// by default, the Apple tools do not seem to implement this optimization, so set this value to <see langword="false"/> if you
|
||||
/// want to maintain binary compatibility with the Apple tools.
|
||||
/// </remarks>
|
||||
public bool ReuseObjectIds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds out the minimum binary property list format version that
|
||||
/// can be used to save the given NSObject tree.
|
||||
@@ -173,18 +188,18 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
/// <param name="outStr">The output stream into which the binary property list will be written</param>
|
||||
/// <exception cref="IOException">If an error occured while writing to the stream</exception>
|
||||
BinaryPropertyListWriter(Stream outStr)
|
||||
public BinaryPropertyListWriter(Stream outStr)
|
||||
{
|
||||
outStream = outStr;
|
||||
}
|
||||
|
||||
BinaryPropertyListWriter(Stream outStr, int version)
|
||||
public BinaryPropertyListWriter(Stream outStr, int version)
|
||||
{
|
||||
this.version = version;
|
||||
outStream = outStr;
|
||||
}
|
||||
|
||||
void Write(NSObject root)
|
||||
public void Write(NSObject root)
|
||||
{
|
||||
// magic bytes
|
||||
Write(new[] { (byte)'b', (byte)'p', (byte)'l', (byte)'i', (byte)'s', (byte)'t' });
|
||||
@@ -269,7 +284,14 @@ namespace Claunia.PropertyList
|
||||
|
||||
internal void AssignID(NSObject obj)
|
||||
{
|
||||
if (obj is UID || obj is NSArray)
|
||||
// If binary compatibility with the Apple format is required,
|
||||
// UID, NSArray and NSString objects are assigned a new ID,
|
||||
// even if they already exist in the file.
|
||||
if (!this.ReuseObjectIds && (obj is UID || obj is NSNumber || obj is NSArray))
|
||||
{
|
||||
idMap.Add(obj);
|
||||
}
|
||||
else if (!this.ReuseObjectIds && obj is NSString && !IsSerializationPrimitive((NSString)obj))
|
||||
{
|
||||
idMap.Add(obj);
|
||||
}
|
||||
@@ -279,17 +301,22 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsSerializationPrimitive(NSString obj)
|
||||
{
|
||||
return obj != null && obj.Content.StartsWith("$") || obj.Content.StartsWith("NS");
|
||||
}
|
||||
|
||||
internal int GetID(NSObject obj)
|
||||
{
|
||||
if (obj is UID)
|
||||
if (!this.ReuseObjectIds && obj is UID)
|
||||
{
|
||||
var uid = obj as UID;
|
||||
var first = idMap.OfType<UID>().First(v => NSObject.ArrayEquals(v.Bytes, uid.Bytes));
|
||||
return idMap.IndexOf(first);
|
||||
}
|
||||
else if (obj is NSArray)
|
||||
else if (!this.ReuseObjectIds && (obj is NSArray || (obj is NSString && !IsSerializationPrimitive((NSString)obj))))
|
||||
{
|
||||
int index = 0;
|
||||
int index = -1;
|
||||
|
||||
for (int i = 0; i < idMap.Count; i++)
|
||||
{
|
||||
@@ -300,6 +327,11 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
}
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -45,12 +45,17 @@ namespace Claunia.PropertyList
|
||||
{
|
||||
readonly Dictionary<string, NSObject> dict;
|
||||
|
||||
// Maps the keys in this dictionary to their NSString equivalent. Makes sure the NSString
|
||||
// object remains constant accross calls to AssignIDs and ToBinary
|
||||
readonly Dictionary<string, NSString> keys;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty NSDictionary.
|
||||
/// </summary>
|
||||
public NSDictionary()
|
||||
{
|
||||
dict = new Dictionary<string, NSObject>();
|
||||
keys = new Dictionary<string, NSString>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -366,7 +371,7 @@ namespace Claunia.PropertyList
|
||||
|
||||
foreach (KeyValuePair<string, NSObject> entry in dict)
|
||||
{
|
||||
new NSString(entry.Key).AssignIDs(outPlist);
|
||||
keys[entry.Key].AssignIDs(outPlist);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, NSObject> entry in dict)
|
||||
@@ -380,7 +385,7 @@ namespace Claunia.PropertyList
|
||||
outPlist.WriteIntHeader(0xD, dict.Count);
|
||||
foreach (KeyValuePair<String, NSObject> entry in dict)
|
||||
{
|
||||
outPlist.WriteID(outPlist.GetID(new NSString(entry.Key)));
|
||||
outPlist.WriteID(outPlist.GetID(keys[entry.Key]));
|
||||
}
|
||||
foreach (KeyValuePair<String, NSObject> entry in dict)
|
||||
{
|
||||
@@ -488,6 +493,7 @@ namespace Claunia.PropertyList
|
||||
public void Add(string key, NSObject value)
|
||||
{
|
||||
dict.Add(key, value);
|
||||
keys.Add(key, new NSString(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -516,6 +522,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="key">Key.</param>
|
||||
public bool Remove(string key)
|
||||
{
|
||||
keys.Remove(key);
|
||||
return dict.Remove(key);
|
||||
}
|
||||
|
||||
@@ -534,7 +541,7 @@ namespace Claunia.PropertyList
|
||||
/// Gets or sets the <see cref="Claunia.PropertyList.NSObject"/> at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
public NSObject this [string index]
|
||||
public NSObject this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -542,6 +549,11 @@ namespace Claunia.PropertyList
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!keys.ContainsKey(index))
|
||||
{
|
||||
keys.Add(index, new NSString(index));
|
||||
}
|
||||
|
||||
dict[index] = value;
|
||||
}
|
||||
}
|
||||
@@ -579,6 +591,7 @@ namespace Claunia.PropertyList
|
||||
/// <param name="item">Item.</param>
|
||||
public void Add(KeyValuePair<string, NSObject> item)
|
||||
{
|
||||
keys.Add(item.Key, new NSString(item.Key));
|
||||
dict.Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
@@ -587,6 +600,7 @@ namespace Claunia.PropertyList
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
keys.Clear();
|
||||
dict.Clear();
|
||||
}
|
||||
|
||||
@@ -618,6 +632,7 @@ namespace Claunia.PropertyList
|
||||
/// <returns><c>true</c> if successfully removed, <c>false</c> if not, or if item is not in current instance.</returns>
|
||||
public bool Remove(KeyValuePair<string, NSObject> item)
|
||||
{
|
||||
keys.Remove(item.Key);
|
||||
return dict.Remove(item.Key);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user