From bb8503c18e31f6805356a8de487f55bf7a66d992 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Fri, 8 Nov 2024 14:01:16 +0100 Subject: [PATCH] Optimize some methods in RightsManagementEncryptionTransform, reduce allocs (#9851) * Use Span in Base32EncodeWithoutPadding and MakeUseLicenseStreamName * Spanify ParseTypePrefixedUserName as well to remove an allocation * Use StartsWith instead of CompareOrdinal in EnumUseLicenseStreams * Use string.Concat to prevent DefaultInterpolatedStringHandler creation --- .../RightsManagementEncryptionTransform.cs | 81 +++++-------------- 1 file changed, 18 insertions(+), 63 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs index c10a551119d..a020ac9a4fb 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs @@ -649,11 +649,7 @@ ref bool stop /// If the RM information in this file cannot be read by the current version of /// this class. /// - internal void - EnumUseLicenseStreams( - UseLicenseStreamCallback callback, - object param - ) + internal void EnumUseLicenseStreams(UseLicenseStreamCallback callback, object param) { ArgumentNullException.ThrowIfNull(callback); @@ -662,11 +658,7 @@ object param foreach (StreamInfo si in _useLicenseStorage.GetStreams()) { // Stream names: we preserve casing, but do case-insensitive comparison (Native CompoundFile API behavior) - if (String.CompareOrdinal( - LicenseStreamNamePrefix.ToUpperInvariant(), 0, - si.Name.ToUpperInvariant(), 0, - LicenseStreamNamePrefixLength - ) == 0) + if (si.Name.StartsWith(LicenseStreamNamePrefix, StringComparison.OrdinalIgnoreCase)) { callback(this, si, param, ref stop); if (stop) @@ -741,9 +733,7 @@ out ContentUser user // If the type-prefixed name is not in a valid format, a FileFormatException // will be thrown. // - AuthenticationType authenticationType; - string userName; - ParseTypePrefixedUserName(typePrefixedUserName, out authenticationType, out userName); + ParseTypePrefixedUserName(typePrefixedUserName, out AuthenticationType authenticationType, out string userName); user = new ContentUser(userName, authenticationType); // @@ -872,11 +862,7 @@ ref bool stop /// SaveUseLicense has removed any existing use licenses for this /// user before calling this internal function. /// - internal void - SaveUseLicenseForUser( - ContentUser user, - UseLicense useLicense - ) + internal void SaveUseLicenseForUser(ContentUser user, UseLicense useLicense) { // // Generate a unique name for the use license stream, and create the stream. @@ -1007,10 +993,7 @@ internal UseLicense UseLicense /// /// This function dose NOT produce a proper Base32Encoding since it will NOT produce proper padding. /// - private static char[] - Base32EncodeWithoutPadding( - byte[] bytes - ) + private static ReadOnlySpan Base32EncodeWithoutPadding(ReadOnlySpan bytes, Span initialBuffer) { int numBytes = bytes.Length; int numBits = checked (numBytes * 8); @@ -1020,7 +1003,7 @@ byte[] bytes if (numBits % 5 != 0) ++numChars; - char[] chars = new char[numChars]; + Span chars = initialBuffer.Length >= numChars ? initialBuffer.Slice(0, numChars) : new char[numChars]; for (int iChar = 0; iChar < numChars; ++iChar) { @@ -1055,8 +1038,10 @@ byte[] bytes /// private static string MakeUseLicenseStreamName() { - return LicenseStreamNamePrefix + - new string(Base32EncodeWithoutPadding(Guid.NewGuid().ToByteArray())); + Span guidBytes = stackalloc byte[16]; + Guid.NewGuid().TryWriteBytes(guidBytes); + + return string.Concat(LicenseStreamNamePrefix, Base32EncodeWithoutPadding(guidBytes, stackalloc char[26])); } /// @@ -1088,21 +1073,12 @@ ContentUser user /// /// The user's ID. /// - private static void - ParseTypePrefixedUserName( - string typePrefixedUserName, - out AuthenticationType authenticationType, - out string userName - ) + private static void ParseTypePrefixedUserName(string typePrefixedUserName, out AuthenticationType authenticationType, out string userName) { - // // We don't actually know the authentication type yet, and we might find that // the type-prefixed user name doesn't even specify a valid authentication // type. But we have to assign to authenticationType because it's an out // parameter. - // - authenticationType = AuthenticationType.Windows; - int colonIndex = typePrefixedUserName.IndexOf(':'); if (colonIndex < 1 || colonIndex >= typePrefixedUserName.Length - 1) { @@ -1112,33 +1088,15 @@ out string userName // No need to use checked{} here since colonIndex cannot be >= to (max int - 1) userName = typePrefixedUserName.Substring(colonIndex + 1); - string authenticationTypeString = typePrefixedUserName.Substring(0, colonIndex); - bool validEnum = false; + // Usernames: Case-Insensitive comparison + ReadOnlySpan authenticationSpan = typePrefixedUserName.AsSpan(0, colonIndex); - // user names: case-insensitive comparison - if (string.Equals(authenticationTypeString, nameof(AuthenticationType.Windows), StringComparison.OrdinalIgnoreCase)) - { + if (authenticationSpan.Equals(nameof(AuthenticationType.Windows), StringComparison.OrdinalIgnoreCase)) authenticationType = AuthenticationType.Windows; - validEnum = true; - } - else if (string.Equals(authenticationTypeString, nameof(AuthenticationType.Passport), StringComparison.OrdinalIgnoreCase)) - { + else if (authenticationSpan.Equals(nameof(AuthenticationType.Passport), StringComparison.OrdinalIgnoreCase)) authenticationType = AuthenticationType.Passport; - validEnum = true; - } - - // - // Didn't find a matching enumeration constant. - // - if (!validEnum) - { - throw new FileFormatException( - SR.Format( - SR.InvalidAuthenticationTypeString, - typePrefixedUserName - ) - ); - } + else // Didn't find a matching enumeration constant. + throw new FileFormatException(SR.Format(SR.InvalidAuthenticationTypeString, typePrefixedUserName)); } /// @@ -1215,9 +1173,7 @@ BinaryReader utf8Reader // If the type-prefixed name is not in a valid format, a FileFormatException // will be thrown. // - AuthenticationType authenticationType; - string userName; - ParseTypePrefixedUserName(typePrefixedUserName, out authenticationType, out userName); + ParseTypePrefixedUserName(typePrefixedUserName, out AuthenticationType authenticationType, out string userName); return new ContentUser(userName, authenticationType); } @@ -1378,7 +1334,6 @@ Encoding encoding // All use licenses reside in streams whose names begin with this prefix: // private const string LicenseStreamNamePrefix = "EUL-"; - private static readonly int LicenseStreamNamePrefixLength = LicenseStreamNamePrefix.Length; // // The RM version information for the current version of this class.