diff --git a/Penumbra.GameData/ByteString/ByteStringFunctions.Case.cs b/Penumbra.GameData/ByteString/ByteStringFunctions.Case.cs index 7d9a94f9..aeda4bfd 100644 --- a/Penumbra.GameData/ByteString/ByteStringFunctions.Case.cs +++ b/Penumbra.GameData/ByteString/ByteStringFunctions.Case.cs @@ -9,6 +9,10 @@ public static unsafe partial class ByteStringFunctions .Select( i => ( byte )char.ToLowerInvariant( ( char )i ) ) .ToArray(); + private static readonly byte[] AsciiUpperCaseBytes = Enumerable.Range( 0, 256 ) + .Select( i => ( byte )char.ToUpperInvariant( ( char )i ) ) + .ToArray(); + // Convert a byte to its ASCII-lowercase version. public static byte AsciiToLower( byte b ) => AsciiLowerCaseBytes[ b ]; @@ -17,6 +21,14 @@ public static unsafe partial class ByteStringFunctions public static bool AsciiIsLower( byte b ) => AsciiToLower( b ) == b; + // Convert a byte to its ASCII-uppercase version. + public static byte AsciiToUpper( byte b ) + => AsciiUpperCaseBytes[ b ]; + + // Check if a byte is ASCII-uppercase. + public static bool AsciiIsUpper( byte b ) + => AsciiToUpper( b ) == b; + // Check if a byte array of given length is ASCII-lowercase. public static bool IsAsciiLowerCase( byte* path, int length ) { diff --git a/Penumbra.GameData/ByteString/Utf8String.Manipulation.cs b/Penumbra.GameData/ByteString/Utf8String.Manipulation.cs index 2a941020..c4332a1d 100644 --- a/Penumbra.GameData/ByteString/Utf8String.Manipulation.cs +++ b/Penumbra.GameData/ByteString/Utf8String.Manipulation.cs @@ -25,6 +25,32 @@ public sealed unsafe partial class Utf8String ? new Utf8String().Setup( ByteStringFunctions.AsciiToLower( _path, Length ), Length, null, true, true, true, IsAsciiInternal ) : this; + // Convert the ascii portion of the string to mixed case (i.e. capitalize every first letter in a word) + // Clones the string. + public Utf8String AsciiToMixed() + { + var length = Length; + if( length == 0 ) + { + return Empty; + } + + var ret = Clone(); + var previousWhitespace = true; + var end = ret.Path + length; + for( var ptr = ret.Path; ptr < end; ++ptr ) + { + if( previousWhitespace ) + { + *ptr = ByteStringFunctions.AsciiToUpper( *ptr ); + } + + previousWhitespace = char.IsWhiteSpace( ( char )*ptr ); + } + + return ret; + } + // Convert the ascii portion of the string to lowercase. // Guaranteed to create an owned copy. public Utf8String AsciiToLowerClone() @@ -37,7 +63,7 @@ public sealed unsafe partial class Utf8String { var ret = new Utf8String(); ret._length = _length | OwnedFlag | NullTerminatedFlag; - ret._path = ByteStringFunctions.CopyString(Path, Length); + ret._path = ByteStringFunctions.CopyString( Path, Length ); ret._crc32 = Crc32; return ret; }