From 19c1e47db2a92455681a31343266d8ec7109d32f Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 19 Jun 2018 14:40:51 +0200 Subject: [PATCH] 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 --- plist-cil/BinaryPropertyListParser.cs | 22 ++++++++-------- plist-cil/NSDictionary.cs | 15 +++++++++-- plist-cil/PropertyListParser.cs | 36 ++++++++++++++++----------- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/plist-cil/BinaryPropertyListParser.cs b/plist-cil/BinaryPropertyListParser.cs index b4c4462..33818e8 100644 --- a/plist-cil/BinaryPropertyListParser.cs +++ b/plist-cil/BinaryPropertyListParser.cs @@ -119,20 +119,20 @@ namespace Claunia.PropertyList /// When the property list's format could not be parsed. private NSObject DoParse(ReadOnlySpan 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)); diff --git a/plist-cil/NSDictionary.cs b/plist-cil/NSDictionary.cs index 8d76a67..721dd4f 100644 --- a/plist-cil/NSDictionary.cs +++ b/plist-cil/NSDictionary.cs @@ -49,13 +49,24 @@ namespace Claunia.PropertyList // object remains constant accross calls to AssignIDs and ToBinary readonly Dictionary keys; + /// + /// Creates a new empty NSDictionary with a specific capacity. + /// + /// + /// The capacity of the dictionary. + /// + public NSDictionary(int capacity) + { + dict = new Dictionary(capacity); + keys = new Dictionary(capacity); + } + /// /// Creates a new empty NSDictionary. /// public NSDictionary() + : this(0) { - dict = new Dictionary(); - keys = new Dictionary(); } /// diff --git a/plist-cil/PropertyListParser.cs b/plist-cil/PropertyListParser.cs index ac7f572..bfce752 100644 --- a/plist-cil/PropertyListParser.cs +++ b/plist-cil/PropertyListParser.cs @@ -49,22 +49,34 @@ namespace Claunia.PropertyList /// /// The type of the property list /// The very first bytes of data of the property list (minus any whitespace) as a string - static int DetermineType(string dataBeginning) + static int DetermineTypeExact(ReadOnlySpan 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; + } } /// @@ -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); } /// @@ -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; }