Penumbra/Penumbra.GameData/ByteString/ByteStringFunctions.Construction.cs

68 lines
No EOL
1.9 KiB
C#

using System;
using System.Runtime.InteropServices;
using System.Text;
using Penumbra.GameData.Util;
namespace Penumbra.GameData.ByteString;
public static unsafe partial class ByteStringFunctions
{
// Used for static null-terminators.
public class NullTerminator
{
public readonly byte* NullBytePtr;
public NullTerminator()
{
NullBytePtr = ( byte* )Marshal.AllocHGlobal( 1 );
*NullBytePtr = 0;
}
~NullTerminator()
=> Marshal.FreeHGlobal( ( IntPtr )NullBytePtr );
}
// Convert a C# unicode-string to an unmanaged UTF8-byte array and return the pointer.
// If the length would exceed the given maxLength, return a nullpointer instead.
public static byte* Utf8FromString( string s, out int length, int maxLength = int.MaxValue )
{
length = Encoding.UTF8.GetByteCount( s );
if( length >= maxLength )
{
return null;
}
var path = ( byte* )Marshal.AllocHGlobal( length + 1 );
fixed( char* ptr = s )
{
Encoding.UTF8.GetBytes( ptr, length, path, length + 1 );
}
path[ length ] = 0;
return path;
}
// Create a copy of a given string and return the pointer.
public static byte* CopyString( byte* path, int length )
{
var ret = ( byte* )Marshal.AllocHGlobal( length + 1 );
Functions.MemCpyUnchecked( ret, path, length );
ret[ length ] = 0;
return ret;
}
// Check the length of a null-terminated byte array no longer than the given maxLength.
public static int CheckLength( byte* path, int maxLength = int.MaxValue )
{
var end = path + maxLength;
for( var it = path; it < end; ++it )
{
if( *it == 0 )
{
return ( int )( it - path );
}
}
throw new ArgumentOutOfRangeException( "Null-terminated path too long" );
}
}