2019-06-25 19:10:57 -04:00
using System ;
using System.Diagnostics.CodeAnalysis ;
using System.Runtime.InteropServices ;
using System.Security ;
using Vanara.Extensions ;
namespace Vanara.InteropServices
{
/// <summary>Base abstract class for a string handler based on <see cref="SafeMemoryHandle{TMem}"/>.</summary>
/// <typeparam name="TMem">The type of the memory.</typeparam>
/// <seealso cref="Vanara.InteropServices.SafeMemoryHandle{TMem}"/>
2019-08-27 10:41:39 -04:00
public abstract class SafeMemString < TMem > : SafeMemoryHandle < TMem > , IEquatable < SafeMemString < TMem > > , IEquatable < string > , IComparable < SafeMemString < TMem > > , IComparable < string > where TMem : IMemoryMethods , new ( )
2019-06-25 19:10:57 -04:00
{
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
/// <param name="s">The string value.</param>
/// <param name="charSet">The character set.</param>
protected SafeMemString ( string s , CharSet charSet = CharSet . Unicode ) : this ( s , s is null ? 0 : s . Length + 1 , charSet )
{
}
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
/// <param name="s">The string value.</param>
/// <param name="capacity">The capacity of the buffer, in characters.</param>
/// <param name="charSet">The character set.</param>
2022-03-10 19:43:56 -05:00
protected SafeMemString ( string s , int capacity , CharSet charSet = CharSet . Unicode ) : this ( capacity , charSet ) = > StringHelper . Write ( s , handle , out _ , true , charSet , Size ) ;
2019-06-25 19:10:57 -04:00
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
/// <param name="s">The string value.</param>
/// <param name="charSet">The character set.</param>
protected SafeMemString ( SecureString s , CharSet charSet = CharSet . Unicode ) : this ( IntPtr . Zero , charSet )
{
2022-03-10 19:43:56 -05:00
SetHandle ( StringHelper . AllocSecureString ( s , charSet , mm . AllocMem , out int sz ) ) ;
2019-06-25 19:10:57 -04:00
base . sz = sz ;
}
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
/// <param name="charLen">The size of the buffer in characters, including the null character terminator.</param>
/// <param name="charSet">The character set.</param>
2022-03-10 19:43:56 -05:00
protected SafeMemString ( int charLen , CharSet charSet = CharSet . Unicode ) : base ( charLen * StringHelper . GetCharSize ( charSet ) ) = > CharSet = charSet ;
2019-06-25 19:10:57 -04:00
/// <summary>Prevents a default instance of the <see cref="SafeMemString{TMem}"/> class from being created.</summary>
[ExcludeFromCodeCoverage]
protected SafeMemString ( ) : base ( 0 ) { }
2019-08-27 10:41:39 -04:00
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
2019-06-25 19:10:57 -04:00
/// <param name="ptr">The PTR.</param>
/// <param name="charSet">The character set.</param>
/// <param name="ownsHandle"><c>true</c> to reliably release the handle during finalization; <c>false</c> to prevent it.</param>
2019-08-23 13:52:14 -04:00
/// <param name="allocatedBytes">The number of bytes allocated to <paramref name="ptr"/>.</param>
2019-06-25 19:10:57 -04:00
[ExcludeFromCodeCoverage]
2022-03-10 19:43:56 -05:00
protected SafeMemString ( IntPtr ptr , CharSet charSet = CharSet . Unicode , bool ownsHandle = true , PInvoke . SizeT allocatedBytes = default ) : base ( ptr , allocatedBytes , ownsHandle ) = > CharSet = charSet ;
/// <summary>Gets or sets the <see cref="System.Char"/> at the specified index.</summary>
/// <value>The <see cref="System.Char"/>.</value>
/// <param name="index">The index of the character in the in-memory string.</param>
/// <returns>The character.</returns>
/// <exception cref="System.IndexOutOfRangeException"></exception>
public char this [ int index ]
2019-06-25 19:10:57 -04:00
{
2022-03-10 19:43:56 -05:00
get
{
var cs = StringHelper . GetCharSize ( CharSet ) ;
if ( index * cs > = Capacity | | index < 0 ) throw new IndexOutOfRangeException ( ) ;
return CharSet = = CharSet . Ansi ? System . Text . Encoding . ASCII . GetChars ( GetBytes ( index * cs , cs ) ) [ 0 ] : System . Text . Encoding . Unicode . GetChars ( GetBytes ( index * cs , cs ) ) [ 0 ] ;
}
set
{
var cs = StringHelper . GetCharSize ( CharSet ) ;
if ( index * cs > = Capacity | | index < 0 ) throw new IndexOutOfRangeException ( ) ;
var bytes = CharSet = = CharSet . Ansi ? System . Text . Encoding . ASCII . GetBytes ( new [ ] { value } ) : System . Text . Encoding . Unicode . GetBytes ( new [ ] { value } ) ;
handle . Write ( bytes , index * cs , Size ) ;
}
2019-06-25 19:10:57 -04:00
}
/// <summary>Gets the number of allocated characters or 0 if the size is unknown (for example if it is holding a <see cref="SecureString"/>.</summary>
/// <value>The number of allocated characters.</value>
2019-08-23 13:52:14 -04:00
public int Capacity
{
get = > Size / StringHelper . GetCharSize ( CharSet ) ;
set = > Size = value * StringHelper . GetCharSize ( CharSet ) ;
}
/// <summary>Gets the character set of the assigned string.</summary>
/// <value>The character set.</value>
public CharSet CharSet { get ; private set ; } = CharSet . Unicode ;
2019-06-25 19:10:57 -04:00
/// <summary>Gets the number of characters in the current <see cref="SafeMemString{TMem}"/> object.</summary>
public int Length = > ToString ( ) . Length ;
2022-03-10 19:43:56 -05:00
/// <summary>Performs an explicit conversion from <see cref="SafeMemString{TMem}"/> to <see cref="char"/>.</summary>
2019-08-27 10:41:39 -04:00
/// <param name="s">The <see cref="SafeMemString{TMem}"/> instance.</param>
/// <returns>The result of the conversion.</returns>
/// <exception cref="InvalidCastException">Cannot convert an ANSI string to a Char pointer.</exception>
public static unsafe explicit operator char * ( SafeMemString < TMem > s ) = > s . CharSet = = CharSet . Unicode ? ( char * ) ( void * ) s . handle : throw new InvalidCastException ( "Cannot convert an ANSI string to a Char pointer." ) ;
2019-06-25 19:10:57 -04:00
/// <summary>Returns the value of the <see cref="SafeHandle.handle"/> field.</summary>
/// <param name="s">The <see cref="SafeMemString{TMem}"/> instance.</param>
/// <returns>
/// An <see cref="IntPtr"/> representing the value of the handle field. If the handle has been marked invalid with
/// <see cref="SafeHandle.SetHandleAsInvalid"/>, this method still returns the original handle value, which can be a stale value.
/// </returns>
2019-08-23 13:52:14 -04:00
public static implicit operator IntPtr ( SafeMemString < TMem > s ) = > s . DangerousGetHandle ( ) ;
2019-06-25 19:10:57 -04:00
/// <summary>Returns the string value held by a <see cref="SafeMemString{TMem}"/>.</summary>
/// <param name="s">The <see cref="SafeMemString{TMem}"/> instance.</param>
/// <returns>
2022-03-10 19:43:56 -05:00
/// A <see cref="string"/> value held by the <see cref="SafeMemString{TMem}"/> or <c>null</c> if the handle or value is invalid.
2019-06-25 19:10:57 -04:00
/// </returns>
public static implicit operator string ( SafeMemString < TMem > s ) = > s ? . ToString ( ) ;
2019-08-27 10:41:39 -04:00
/// <summary>Implements the operator !=.</summary>
/// <param name="s1">The left value.</param>
/// <param name="s2">The right value.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ! = ( SafeMemString < TMem > s1 , SafeMemString < TMem > s2 ) = > ! s1 . Equals ( s2 ) ;
/// <summary>Implements the operator ==.</summary>
/// <param name="s1">The left value.</param>
/// <param name="s2">The right value.</param>
/// <returns>The result of the operator.</returns>
public static bool operator = = ( SafeMemString < TMem > s1 , SafeMemString < TMem > s2 ) = > s1 . Equals ( s2 ) ;
/// <summary>Implements the operator !=.</summary>
/// <param name="s1">The left value.</param>
/// <param name="s2">The right value.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ! = ( SafeMemString < TMem > s1 , string s2 ) = > ! s1 . Equals ( s2 ) ;
/// <summary>Implements the operator ==.</summary>
/// <param name="s1">The left value.</param>
/// <param name="s2">The right value.</param>
/// <returns>The result of the operator.</returns>
public static bool operator = = ( SafeMemString < TMem > s1 , string s2 ) = > s1 . Equals ( s2 ) ;
/// <summary>Compares the current object with another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following
/// meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal
/// to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
public int CompareTo ( SafeMemString < TMem > other ) = > string . Compare ( this , other ) ;
/// <summary>Compares the current object with another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following
/// meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal
/// to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
public int CompareTo ( string other ) = > string . Compare ( this , other ) ;
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
public bool Equals ( SafeMemString < TMem > other ) = > string . Equals ( this , other ) ;
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
public bool Equals ( string other ) = > string . Equals ( this , other ) ;
2022-03-10 19:43:56 -05:00
/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals ( object obj ) = > ReferenceEquals ( this , obj ) | | obj switch
2019-08-27 10:41:39 -04:00
{
2022-03-10 19:43:56 -05:00
null = > false ,
SafeMemString < TMem > ms = > Equals ( ms ) ,
string s = > Equals ( s ) ,
SafeAllocatedMemoryHandle m = > m = = handle ,
_ = > false ,
} ;
2019-08-27 10:41:39 -04:00
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode ( ) = > ToString ( ) ? . GetHashCode ( ) ? ? 0 ;
2019-08-23 13:52:14 -04:00
2019-09-16 09:55:18 -04:00
/// <summary>Assigns a new string to this memory.</summary>
/// <param name="value">The string value. This value can be <see langword="null"/>, but its length cannot be greater than the current <see cref="Capacity"/>.</param>
2022-03-10 19:43:56 -05:00
public virtual void Set ( string value ) = > StringHelper . Write ( value , handle , out _ , true , CharSet , Size ) ;
2019-09-16 09:55:18 -04:00
2019-06-25 19:10:57 -04:00
/// <summary>Returns the string value held by this instance.</summary>
2022-03-10 19:43:56 -05:00
/// <returns>A <see cref="string"/> value held by this instance or <c>null</c> if the handle is invalid.</returns>
2019-10-08 15:29:30 -04:00
public override string ToString ( ) = > IsInvalid ? null : StringHelper . GetString ( handle , CharSet , Size = = 0 ? long . MaxValue : ( long ) Size ) ;
2019-06-25 19:10:57 -04:00
}
}