using System;
using System.Runtime.InteropServices;
namespace LibGit2Sharp.Core
{
///
/// This marshaler is to be used for capturing a UTF-8 string owned by libgit2 and
/// converting it to a managed FilePath instance. The marshaler will not attempt to
/// free the native pointer after conversion, because the memory is owned by libgit2.
///
/// Use this marshaler for return values, for example:
/// [return: MarshalAs(UnmanagedType.CustomMarshaler,
/// MarshalTypeRef = typeof(FilePathNoCleanupMarshaler))]
///
internal class FilePathNoCleanupMarshaler : FilePathMarshaler
{
private static readonly FilePathNoCleanupMarshaler staticInstance = new FilePathNoCleanupMarshaler();
public static new ICustomMarshaler GetInstance(String cookie)
{
return staticInstance;
}
#region ICustomMarshaler
public override void CleanUpNativeData(IntPtr pNativeData)
{
}
#endregion
}
///
/// This marshaler is to be used for sending managed FilePath instances to libgit2.
/// The marshaler will allocate a buffer in native memory to hold the UTF-8 string
/// and perform the encoding conversion using that buffer as the target. The pointer
/// received by libgit2 will be to this buffer. After the function call completes, the
/// native buffer is freed.
///
/// Use this marshaler for function parameters, for example:
/// [DllImport(libgit2)]
/// internal static extern int git_index_open(out IndexSafeHandle index,
/// [MarshalAs(UnmanagedType.CustomMarshaler,
/// MarshalTypeRef = typeof(FilePathMarshaler))] FilePath indexpath);
///
internal class FilePathMarshaler : ICustomMarshaler
{
private static readonly FilePathMarshaler staticInstance = new FilePathMarshaler();
public static ICustomMarshaler GetInstance(String cookie)
{
return staticInstance;
}
#region ICustomMarshaler
public void CleanUpManagedData(Object managedObj)
{
}
public virtual void CleanUpNativeData(IntPtr pNativeData)
{
if (IntPtr.Zero != pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
}
}
public int GetNativeDataSize()
{
// Not a value type
return -1;
}
public IntPtr MarshalManagedToNative(Object managedObj)
{
if (null == managedObj)
{
return IntPtr.Zero;
}
var filePath = managedObj as FilePath;
if (null == filePath)
{
throw new MarshalDirectiveException("FilePathMarshaler must be used on a FilePath.");
}
return FromManaged(filePath);
}
public Object MarshalNativeToManaged(IntPtr pNativeData)
{
return FromNative(pNativeData);
}
#endregion
public static IntPtr FromManaged(FilePath filePath)
{
if (null == filePath)
{
return IntPtr.Zero;
}
return Utf8Marshaler.FromManaged(filePath.Posix);
}
public static FilePath FromNative(IntPtr pNativeData)
{
if (IntPtr.Zero == pNativeData)
{
return null;
}
if (0 == Marshal.ReadByte(pNativeData))
{
return FilePath.Empty;
}
return Utf8Marshaler.FromNative(pNativeData);
}
public static FilePath FromNative(IntPtr pNativeData, int length)
{
if (0 == length)
{
return FilePath.Empty;
}
return Utf8Marshaler.FromNative(pNativeData, length);
}
}
}