Performance improvements

- Set the capacity of the dictionary of known
- Don't allocate a string to check whether a file is a valid binary property list
This commit is contained in:
Frederik Carlier
2018-06-19 14:40:51 +02:00
parent 5c68ff1b62
commit 19c1e47db2
3 changed files with 46 additions and 27 deletions

View File

@@ -119,20 +119,20 @@ namespace Claunia.PropertyList
/// <exception cref="PropertyListFormatException">When the property list's format could not be parsed.</exception>
private NSObject DoParse(ReadOnlySpan<byte> bytes)
{
string magic = Encoding.ASCII.GetString(
#if NATIVE_SPAN
bytes.Slice(0, 8));
#else
bytes.Slice(0, 8).ToArray());
#endif
if (!magic.StartsWith("bplist", StringComparison.Ordinal))
if(bytes.Length < 8
|| bytes[0] != 'b'
|| bytes[1] != 'p'
|| bytes[2] != 'l'
|| bytes[3] != 'i'
|| bytes[4] != 's'
|| bytes[5] != 't')
{
var magic = Encoding.ASCII.GetString(bytes.Slice(0, 8).ToArray());
throw new PropertyListFormatException("The given data is no binary property list. Wrong magic bytes: " + magic);
}
majorVersion = magic[6] - 0x30; //ASCII number
minorVersion = magic[7] - 0x30; //ASCII number
majorVersion = bytes[6] - 0x30; //ASCII number
minorVersion = bytes[7] - 0x30; //ASCII number
// 0.0 - OS X Tiger and earlier
// 0.1 - Leopard
@@ -366,7 +366,7 @@ namespace Claunia.PropertyList
ReadLengthAndOffset(bytes, objInfo, offset, out int length, out int contentOffset);
//System.out.println("Parsing dictionary #"+obj);
NSDictionary dict = new NSDictionary();
NSDictionary dict = new NSDictionary(length);
for (int i = 0; i < length; i++)
{
int keyRef = (int)ParseUnsignedInt(bytes.Slice(offset + contentOffset + i * objectRefSize, objectRefSize));

View File

@@ -49,13 +49,24 @@ namespace Claunia.PropertyList
// object remains constant accross calls to AssignIDs and ToBinary
readonly Dictionary<string, NSString> keys;
/// <summary>
/// Creates a new empty NSDictionary with a specific capacity.
/// </summary>
/// <param name="capacity">
/// The capacity of the dictionary.
/// </param>
public NSDictionary(int capacity)
{
dict = new Dictionary<string, NSObject>(capacity);
keys = new Dictionary<string, NSString>(capacity);
}
/// <summary>
/// Creates a new empty NSDictionary.
/// </summary>
public NSDictionary()
: this(0)
{
dict = new Dictionary<string, NSObject>();
keys = new Dictionary<string, NSString>();
}
/// <summary>

View File

@@ -49,22 +49,34 @@ 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>
static int DetermineType(string dataBeginning)
static int DetermineTypeExact(ReadOnlySpan<byte> dataBeginning)
{
dataBeginning = dataBeginning.Trim();
if (dataBeginning.Length == 0)
{
return TYPE_ERROR_BLANK;
}
if (dataBeginning.StartsWith("bplist"))
{
return TYPE_BINARY;
}
if (dataBeginning.StartsWith("(") || dataBeginning.StartsWith("{") || dataBeginning.StartsWith("/"))
else if (dataBeginning[0] == '(' || dataBeginning[0] == '{' || dataBeginning[0] == '/')
{
return TYPE_ASCII;
}
return dataBeginning.StartsWith("<") ? TYPE_XML : TYPE_ERROR_UNKNOWN;
else if (dataBeginning[0] == '<')
{
return TYPE_XML;
}
else if (dataBeginning.Length >= 6
&& dataBeginning[0] == 'b'
&& dataBeginning[1] == 'p'
&& dataBeginning[2] == 'l'
&& dataBeginning[3] == 'i'
&& dataBeginning[4] == 's'
&& dataBeginning[5] == 't')
{
return TYPE_BINARY;
}
else
{
return TYPE_ERROR_UNKNOWN;
}
}
/// <summary>
@@ -90,11 +102,7 @@ namespace Claunia.PropertyList
}
var header = bytes.Slice(offset, Math.Min(8, bytes.Length - offset));
#if NATIVE_SPAN
return DetermineType(Encoding.ASCII.GetString(header));
#else
return DetermineType(Encoding.ASCII.GetString(header.ToArray(), 0, header.Length));
#endif
return DetermineTypeExact(header);
}
/// <summary>
@@ -138,7 +146,7 @@ namespace Claunia.PropertyList
magicBytes[0] = (byte)b;
int read = fs.Read(magicBytes, 1, 7);
int type = DetermineType(Encoding.ASCII.GetString(magicBytes, 0, read));
int type = DetermineTypeExact(magicBytes.AsSpan(0, read));
fs.Seek(mark, SeekOrigin.Begin);
return type;
}