Skip to content

Commit bb8503c

Browse files
authored
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
1 parent c0b716b commit bb8503c

File tree

1 file changed

+18
-63
lines changed

1 file changed

+18
-63
lines changed

src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -649,11 +649,7 @@ ref bool stop
649649
/// If the RM information in this file cannot be read by the current version of
650650
/// this class.
651651
/// </exception>
652-
internal void
653-
EnumUseLicenseStreams(
654-
UseLicenseStreamCallback callback,
655-
object param
656-
)
652+
internal void EnumUseLicenseStreams(UseLicenseStreamCallback callback, object param)
657653
{
658654
ArgumentNullException.ThrowIfNull(callback);
659655

@@ -662,11 +658,7 @@ object param
662658
foreach (StreamInfo si in _useLicenseStorage.GetStreams())
663659
{
664660
// Stream names: we preserve casing, but do case-insensitive comparison (Native CompoundFile API behavior)
665-
if (String.CompareOrdinal(
666-
LicenseStreamNamePrefix.ToUpperInvariant(), 0,
667-
si.Name.ToUpperInvariant(), 0,
668-
LicenseStreamNamePrefixLength
669-
) == 0)
661+
if (si.Name.StartsWith(LicenseStreamNamePrefix, StringComparison.OrdinalIgnoreCase))
670662
{
671663
callback(this, si, param, ref stop);
672664
if (stop)
@@ -741,9 +733,7 @@ out ContentUser user
741733
// If the type-prefixed name is not in a valid format, a FileFormatException
742734
// will be thrown.
743735
//
744-
AuthenticationType authenticationType;
745-
string userName;
746-
ParseTypePrefixedUserName(typePrefixedUserName, out authenticationType, out userName);
736+
ParseTypePrefixedUserName(typePrefixedUserName, out AuthenticationType authenticationType, out string userName);
747737
user = new ContentUser(userName, authenticationType);
748738

749739
//
@@ -872,11 +862,7 @@ ref bool stop
872862
/// SaveUseLicense has removed any existing use licenses for this
873863
/// user before calling this internal function.
874864
/// </remarks>
875-
internal void
876-
SaveUseLicenseForUser(
877-
ContentUser user,
878-
UseLicense useLicense
879-
)
865+
internal void SaveUseLicenseForUser(ContentUser user, UseLicense useLicense)
880866
{
881867
//
882868
// Generate a unique name for the use license stream, and create the stream.
@@ -1007,10 +993,7 @@ internal UseLicense UseLicense
1007993
/// <remarks>
1008994
/// This function dose NOT produce a proper Base32Encoding since it will NOT produce proper padding.
1009995
/// </remarks>
1010-
private static char[]
1011-
Base32EncodeWithoutPadding(
1012-
byte[] bytes
1013-
)
996+
private static ReadOnlySpan<char> Base32EncodeWithoutPadding(ReadOnlySpan<byte> bytes, Span<char> initialBuffer)
1014997
{
1015998
int numBytes = bytes.Length;
1016999
int numBits = checked (numBytes * 8);
@@ -1020,7 +1003,7 @@ byte[] bytes
10201003
if (numBits % 5 != 0)
10211004
++numChars;
10221005

1023-
char[] chars = new char[numChars];
1006+
Span<char> chars = initialBuffer.Length >= numChars ? initialBuffer.Slice(0, numChars) : new char[numChars];
10241007

10251008
for (int iChar = 0; iChar < numChars; ++iChar)
10261009
{
@@ -1055,8 +1038,10 @@ byte[] bytes
10551038
/// </summary>
10561039
private static string MakeUseLicenseStreamName()
10571040
{
1058-
return LicenseStreamNamePrefix +
1059-
new string(Base32EncodeWithoutPadding(Guid.NewGuid().ToByteArray()));
1041+
Span<byte> guidBytes = stackalloc byte[16];
1042+
Guid.NewGuid().TryWriteBytes(guidBytes);
1043+
1044+
return string.Concat(LicenseStreamNamePrefix, Base32EncodeWithoutPadding(guidBytes, stackalloc char[26]));
10601045
}
10611046

10621047
/// <summary>
@@ -1088,21 +1073,12 @@ ContentUser user
10881073
/// <param name="userName">
10891074
/// The user's ID.
10901075
/// </param>
1091-
private static void
1092-
ParseTypePrefixedUserName(
1093-
string typePrefixedUserName,
1094-
out AuthenticationType authenticationType,
1095-
out string userName
1096-
)
1076+
private static void ParseTypePrefixedUserName(string typePrefixedUserName, out AuthenticationType authenticationType, out string userName)
10971077
{
1098-
//
10991078
// We don't actually know the authentication type yet, and we might find that
11001079
// the type-prefixed user name doesn't even specify a valid authentication
11011080
// type. But we have to assign to authenticationType because it's an out
11021081
// parameter.
1103-
//
1104-
authenticationType = AuthenticationType.Windows;
1105-
11061082
int colonIndex = typePrefixedUserName.IndexOf(':');
11071083
if (colonIndex < 1 || colonIndex >= typePrefixedUserName.Length - 1)
11081084
{
@@ -1112,33 +1088,15 @@ out string userName
11121088
// No need to use checked{} here since colonIndex cannot be >= to (max int - 1)
11131089
userName = typePrefixedUserName.Substring(colonIndex + 1);
11141090

1115-
string authenticationTypeString = typePrefixedUserName.Substring(0, colonIndex);
1116-
bool validEnum = false;
1091+
// Usernames: Case-Insensitive comparison
1092+
ReadOnlySpan<char> authenticationSpan = typePrefixedUserName.AsSpan(0, colonIndex);
11171093

1118-
// user names: case-insensitive comparison
1119-
if (string.Equals(authenticationTypeString, nameof(AuthenticationType.Windows), StringComparison.OrdinalIgnoreCase))
1120-
{
1094+
if (authenticationSpan.Equals(nameof(AuthenticationType.Windows), StringComparison.OrdinalIgnoreCase))
11211095
authenticationType = AuthenticationType.Windows;
1122-
validEnum = true;
1123-
}
1124-
else if (string.Equals(authenticationTypeString, nameof(AuthenticationType.Passport), StringComparison.OrdinalIgnoreCase))
1125-
{
1096+
else if (authenticationSpan.Equals(nameof(AuthenticationType.Passport), StringComparison.OrdinalIgnoreCase))
11261097
authenticationType = AuthenticationType.Passport;
1127-
validEnum = true;
1128-
}
1129-
1130-
//
1131-
// Didn't find a matching enumeration constant.
1132-
//
1133-
if (!validEnum)
1134-
{
1135-
throw new FileFormatException(
1136-
SR.Format(
1137-
SR.InvalidAuthenticationTypeString,
1138-
typePrefixedUserName
1139-
)
1140-
);
1141-
}
1098+
else // Didn't find a matching enumeration constant.
1099+
throw new FileFormatException(SR.Format(SR.InvalidAuthenticationTypeString, typePrefixedUserName));
11421100
}
11431101

11441102
/// <summary>
@@ -1215,9 +1173,7 @@ BinaryReader utf8Reader
12151173
// If the type-prefixed name is not in a valid format, a FileFormatException
12161174
// will be thrown.
12171175
//
1218-
AuthenticationType authenticationType;
1219-
string userName;
1220-
ParseTypePrefixedUserName(typePrefixedUserName, out authenticationType, out userName);
1176+
ParseTypePrefixedUserName(typePrefixedUserName, out AuthenticationType authenticationType, out string userName);
12211177
return new ContentUser(userName, authenticationType);
12221178
}
12231179

@@ -1378,7 +1334,6 @@ Encoding encoding
13781334
// All use licenses reside in streams whose names begin with this prefix:
13791335
//
13801336
private const string LicenseStreamNamePrefix = "EUL-";
1381-
private static readonly int LicenseStreamNamePrefixLength = LicenseStreamNamePrefix.Length;
13821337

13831338
//
13841339
// The RM version information for the current version of this class.

0 commit comments

Comments
 (0)