Commit 7f2587fe authored by Martin Finkel's avatar Martin Finkel

Remove Utf8Marshaler

parent 139abe4e
......@@ -58,10 +58,12 @@ namespace LibVLCSharp.Shared
if (password == null)
password = string.Empty;
var usernamePtr = Utf8StringMarshaler.GetInstance().MarshalManagedToNative(username);
var passwordPtr = Utf8StringMarshaler.GetInstance().MarshalManagedToNative(password);
var usernamePtr = username.ToUtf8();
var passwordPtr = password.ToUtf8();
var result = Native.LibVLCDialogPostLogin(_id, usernamePtr, passwordPtr, store) == 0;
var result = MarshalUtils.PerformInteropAndFree(
() => Native.LibVLCDialogPostLogin(_id, usernamePtr, passwordPtr, store),
usernamePtr, passwordPtr) == 0;
_id = IntPtr.Zero;
......
......@@ -126,7 +126,7 @@ namespace LibVLCSharp.Shared
/// </summary>
/// <param name="index">index of the preset, counting from zero</param>
/// <returns>preset name, or empty string if there is no such preset</returns>
public string PresetName(uint index) => (string)Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(Native.LibVLCAudioEqualizerGetPresetName(index));
public string PresetName(uint index) => Native.LibVLCAudioEqualizerGetPresetName(index).FromUtf8();
/// <summary>
/// Get the number of distinct frequency bands for an equalizer.
......
......@@ -636,7 +636,7 @@ namespace LibVLCSharp.Shared
static void OnSnapshotTaken(IntPtr ptr)
{
var filenamePtr = RetrieveEvent(ptr).Union.MediaPlayerSnapshotTaken.Filename;
var filename = (string)Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(filenamePtr);
var filename = filenamePtr.FromUtf8();
_mediaPlayerSnapshotTaken?.Invoke(null, new MediaPlayerSnapshotTakenEventArgs(filename));
}
......@@ -686,7 +686,7 @@ namespace LibVLCSharp.Shared
static void OnAudioDevice(IntPtr ptr)
{
var deviceNamePtr = RetrieveEvent(ptr).Union.AudioDeviceChanged.Device;
var deviceName = (string) Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(deviceNamePtr);
var deviceName = deviceNamePtr.FromUtf8();
_mediaPlayerAudioDevice?.Invoke(null, new MediaPlayerAudioDeviceEventArgs(deviceName));
}
......@@ -817,7 +817,7 @@ namespace LibVLCSharp.Shared
void OnSnapshotTaken(IntPtr ptr)
{
var filenamePtr = RetrieveEvent(ptr).Union.MediaPlayerSnapshotTaken.Filename;
var filename = (string)Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(filenamePtr);
var filename = filenamePtr.FromUtf8();
_mediaPlayerSnapshotTaken?.Invoke(this, new MediaPlayerSnapshotTakenEventArgs(filename));
}
......@@ -860,7 +860,7 @@ namespace LibVLCSharp.Shared
void OnAudioDevice(IntPtr ptr)
{
var deviceNamePtr = RetrieveEvent(ptr).Union.AudioDeviceChanged.Device;
var deviceName = (string)Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(deviceNamePtr);
var deviceName = deviceNamePtr.FromUtf8();
_mediaPlayerAudioDevice?.Invoke(this, new MediaPlayerAudioDeviceEventArgs(deviceName));
}
......
using LibVLCSharp.Shared.Structures;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
......@@ -13,8 +14,7 @@ namespace LibVLCSharp.Shared.Helpers
/// <param name="s">AudioOutputDescriptionStructure from interop</param>
/// <returns>public AudioOutputDescription to be consumed by the user</returns>
internal static AudioOutputDescription Build(this AudioOutputDescriptionStructure s) =>
new AudioOutputDescription(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Name) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Description) as string);
new AudioOutputDescription(s.Name.FromUtf8(), s.Description.FromUtf8());
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
......@@ -22,8 +22,7 @@ namespace LibVLCSharp.Shared.Helpers
/// <param name="s">AudioOutputDeviceStructure from interop</param>
/// <returns>public AudioOutputDevice to be consumed by the user</returns>
internal static AudioOutputDevice Build(this AudioOutputDeviceStructure s) =>
new AudioOutputDevice(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.DeviceIdentifier) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Description) as string);
new AudioOutputDevice(s.DeviceIdentifier.FromUtf8(), s.Description.FromUtf8());
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
......@@ -31,10 +30,7 @@ namespace LibVLCSharp.Shared.Helpers
/// <param name="s">ModuleDescriptionStructure from interop</param>
/// <returns>public ModuleDescription to be consumed by the user</returns>
internal static ModuleDescription Build(this ModuleDescriptionStructure s) =>
new ModuleDescription(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Name) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.ShortName) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.LongName) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Help) as string);
new ModuleDescription(s.Name.FromUtf8(), s.ShortName.FromUtf8(), s.LongName.FromUtf8(), s.Help.FromUtf8());
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
......@@ -42,15 +38,15 @@ namespace LibVLCSharp.Shared.Helpers
/// <param name="s">TrackDescriptionStructure from interop</param>
/// <returns>public TrackDescription to be consumed by the user</returns>
internal static TrackDescription Build(this TrackDescriptionStructure s) =>
new TrackDescription(s.Id, Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Name) as string);
new TrackDescription(s.Id, s.Name.FromUtf8());
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
/// </summary>
/// <param name="s">MediaSlaveStructure from interop</param>
/// <returns>public MediaSlave to be consumed by the user</returns>
internal static MediaSlave Build(this MediaSlaveStructure s) =>
new MediaSlave(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Uri) as string, s.Type, s.Priority);
internal static MediaSlave Build(this MediaSlaveStructure s) =>
new MediaSlave(s.Uri.FromUtf8(), s.Type, s.Priority);
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
......@@ -78,9 +74,6 @@ namespace LibVLCSharp.Shared.Helpers
break;
}
var language = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Language) as string;
var des = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Description) as string;
return new MediaTrack(s.Codec,
s.OriginalFourcc,
s.Id,
......@@ -88,8 +81,8 @@ namespace LibVLCSharp.Shared.Helpers
s.Profile,
s.Level,
new MediaTrackData(audioTrack, videoTrack, subtitleTrack), s.Bitrate,
language,
des);
s.Language.FromUtf8(),
s.Description.FromUtf8());
}
/// <summary>
......@@ -97,7 +90,7 @@ namespace LibVLCSharp.Shared.Helpers
/// </summary>
/// <param name="s">SubtitleTrackStructure from interop</param>
/// <returns>public SubtitleTrack to be consumed by the user</returns>
internal static SubtitleTrack Build(this SubtitleTrackStructure s) => new SubtitleTrack(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Encoding) as string);
internal static SubtitleTrack Build(this SubtitleTrackStructure s) => new SubtitleTrack(s.Encoding.FromUtf8());
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
......@@ -105,21 +98,46 @@ namespace LibVLCSharp.Shared.Helpers
/// <param name="s">MediaDiscovererDescriptionStructure from interop</param>
/// <returns>public MediaDiscovererDescription to be consumed by the user</returns>
internal static MediaDiscovererDescription Build(this MediaDiscovererDescriptionStructure s) =>
new MediaDiscovererDescription(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Name) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.LongName) as string,
s.Category);
new MediaDiscovererDescription(s.Name.FromUtf8(), s.LongName.FromUtf8(), s.Category);
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
/// </summary>
/// <param name="s">RendererDescriptionStructure from interop</param>
/// <returns>public RendererDescription to be consumed by the user</returns>
internal static RendererDescription Build(this RendererDescriptionStructure s) =>
new RendererDescription(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Name) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.LongName) as string);
internal static RendererDescription Build(this RendererDescriptionStructure s) =>
new RendererDescription(s.Name.FromUtf8(), s.LongName.FromUtf8());
internal static IntPtr ToUtf8(this string str) => Utf8StringMarshaler.GetInstance().MarshalManagedToNative(str);
internal static string FromUtf8(this IntPtr nativeString) => Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(nativeString) as string;
internal static IntPtr ToUtf8(this string str)
{
if (string.IsNullOrEmpty(str))
return IntPtr.Zero;
byte[] utf8bytes = Encoding.UTF8.GetBytes(str);
IntPtr ptr = Marshal.AllocCoTaskMem(utf8bytes.Length + 1);
Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length);
Marshal.WriteByte(ptr, utf8bytes.Length, 0);
return ptr;
}
internal static string FromUtf8(this IntPtr nativeString, bool libvlcFree = false)
{
if (nativeString == IntPtr.Zero)
return null;
var bytes = new List<byte>();
for (int offset = 0; ; offset++)
{
byte b = Marshal.ReadByte(nativeString, offset);
if (b == 0)
break;
else bytes.Add(b);
}
var str = Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count);
if (libvlcFree)
MarshalUtils.LibVLCFree(ref nativeString);
return str;
}
}
}
\ No newline at end of file
......@@ -338,11 +338,7 @@ namespace LibVLCSharp.Shared.Helpers
for (var i = 0; i < utf8Args.Length; i++)
{
var bytes = Encoding.UTF8.GetBytes(args[i]);
var buffer = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, buffer, bytes.Length);
Marshal.WriteByte(buffer, bytes.Length, 0);
utf8Args[i] = buffer;
utf8Args[i] = args[i].ToUtf8();
}
return utf8Args;
......@@ -451,6 +447,49 @@ namespace LibVLCSharp.Shared.Helpers
Native.LibVLCFree(ptr);
ptr = IntPtr.Zero;
}
internal static void Free(params IntPtr[] ptrs)
{
foreach (var ptr in ptrs)
Marshal.FreeHGlobal(ptr);
}
/// <summary>
/// Performs the native call, frees the ptrs and returns the result
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="interopCall"></param>
/// <param name="ptrs"></param>
/// <returns></returns>
internal static T PerformInteropAndFree<T>(Func<T> interopCall, params IntPtr[] ptrs)
{
try
{
return interopCall();
}
finally
{
Free(ptrs);
}
}
/// <summary>
/// Performs the native call and frees the ptrs
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="interopCall"></param>
/// <param name="ptrs"></param>
internal static void PerformInteropAndFree(Action interopCall, params IntPtr[] ptrs)
{
try
{
interopCall();
}
finally
{
Free(ptrs);
}
}
}
[AttributeUsage(AttributeTargets.Method)]
......
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
// taken from https://github.com/nikki-nn4/NimDemo
namespace LibVLCSharp.Shared.Helpers
{
/// <summary>
/// Marshal unicode string param to utf-8 string,usage:[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaler))]
/// </summary>
#if !NETSTANDARD1_1
public class Utf8StringMarshaler : ICustomMarshaler
#else
public class Utf8StringMarshaler
#endif
{
private static readonly Utf8StringMarshaler _instance = new Utf8StringMarshaler();
public IntPtr MarshalManagedToNative(object ManagedObj)
{
if (ManagedObj == null)
return IntPtr.Zero;
if (!(ManagedObj is string))
throw new InvalidOperationException("Utf8StringMarshaler:ManagedObj must be string");
byte[] utf8bytes = Encoding.UTF8.GetBytes(ManagedObj as string);
IntPtr ptr = Marshal.AllocCoTaskMem(utf8bytes.Length + 1);
Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length);
Marshal.WriteByte(ptr, utf8bytes.Length, 0);
return ptr;
}
public object MarshalNativeToManaged(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return null;
List<byte> bytes = new List<byte>();
for (int offset = 0; ; offset++)
{
byte b = Marshal.ReadByte(ptr, offset);
if (b == 0)
break;
else bytes.Add(b);
}
var str = Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count);
return str;
}
public void CleanUpManagedData(object ManagedObj)
{
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeCoTaskMem(pNativeData);
pNativeData = IntPtr.Zero;
}
public int GetNativeDataSize()
{
return -1;
}
public static Utf8StringMarshaler GetInstance()
{
return _instance;
}
}
}
......@@ -220,8 +220,11 @@ namespace LibVLCSharp.Shared
/// </summary>
/// <param name="name">interface name, or empty string for default</param>
/// <returns>True if successful, false otherwise</returns>
public bool AddInterface(string name) => Native.LibVLCAddInterface(NativeReference,
Utf8StringMarshaler.GetInstance().MarshalManagedToNative(name)) == 0;
public bool AddInterface(string name)
{
var namePtr = name.ToUtf8();
return MarshalUtils.PerformInteropAndFree(() => Native.LibVLCAddInterface(NativeReference, namePtr) == 0, namePtr);
}
#endif
/// <summary>
/// <para>Registers a callback for the LibVLC exit event. This is mostly useful if</para>
......@@ -254,8 +257,13 @@ namespace LibVLCSharp.Shared
/// <param name="name">human-readable application name, e.g. &quot;FooBar player 1.2.3&quot;</param>
/// <param name="http">HTTP User Agent, e.g. &quot;FooBar/1.2.3 Python/2.6.0&quot;</param>
/// <remarks>LibVLC 1.1.1 or later</remarks>
public void SetUserAgent(string name, string http) => Native.LibVLCSetUserAgent(NativeReference,
Utf8StringMarshaler.GetInstance().MarshalManagedToNative(name), Utf8StringMarshaler.GetInstance().MarshalManagedToNative(http));
public void SetUserAgent(string name, string http)
{
var nameUtf8 = name.ToUtf8();
var httpUtf8 = http.ToUtf8();
MarshalUtils.PerformInteropAndFree(() => Native.LibVLCSetUserAgent(NativeReference, nameUtf8, httpUtf8), nameUtf8, httpUtf8);
}
/// <summary>
/// <para>Sets some meta-information about the application.</para>
......@@ -265,10 +273,15 @@ namespace LibVLCSharp.Shared
/// <param name="version">application version numbers, e.g. &quot;1.2.3&quot;</param>
/// <param name="icon">application icon name, e.g. &quot;foobar&quot;</param>
/// <remarks>LibVLC 2.1.0 or later.</remarks>
public void SetAppId(string id, string version, string icon) => Native.LibVLCSetAppId(NativeReference,
Utf8StringMarshaler.GetInstance().MarshalManagedToNative(id),
Utf8StringMarshaler.GetInstance().MarshalManagedToNative(version),
Utf8StringMarshaler.GetInstance().MarshalManagedToNative(icon));
public void SetAppId(string id, string version, string icon)
{
var idUtf8 = id.ToUtf8();
var versionUtf8 = version.ToUtf8();
var iconUtf8 = icon.ToUtf8();
MarshalUtils.PerformInteropAndFree(() => Native.LibVLCSetAppId(NativeReference, idUtf8, versionUtf8, iconUtf8),
idUtf8, versionUtf8, iconUtf8);
}
/// <summary>Unsets the logging callback.</summary>
/// <remarks>
......@@ -441,12 +454,16 @@ namespace LibVLCSharp.Shared
/// <para>LibVLC 2.1.0 or later.</para>
/// </remarks>
public AudioOutputDevice[] AudioOutputDevices(string audioOutputName) =>
MarshalUtils.Retrieve(() => Native.LibVLCAudioOutputDeviceListGet(NativeReference, Utf8StringMarshaler.GetInstance().MarshalManagedToNative(audioOutputName)),
MarshalUtils.Retrieve(() =>
{
var audioOutputNameUtf8 = audioOutputName.ToUtf8();
return MarshalUtils.PerformInteropAndFree(() => Native.LibVLCAudioOutputDeviceListGet(NativeReference, audioOutputNameUtf8), audioOutputNameUtf8);
},
MarshalUtils.PtrToStructure<AudioOutputDeviceStructure>,
s => s.Build(),
device => device.Next,
Native.LibVLCAudioOutputDeviceListRelease);
/// <summary>Get media discoverer services by category</summary>
/// <param name="discovererCategory">category of services to fetch</param>
/// <returns>the number of media discoverer services (0 on error)</returns>
......@@ -559,7 +576,7 @@ namespace LibVLCSharp.Shared
{
MarshalUtils.Vsprintf(utf8Buffer, format, args);
formattedDecodedMessage = (string)Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(utf8Buffer);
formattedDecodedMessage = utf8Buffer.FromUtf8();
}
finally
{
......@@ -596,8 +613,8 @@ namespace LibVLCSharp.Shared
Native.LibVLCLogGetContext(logContext, out var modulePtr, out var filePtr, out var linePtr);
line = linePtr == UIntPtr.Zero ? null : (uint?)linePtr.ToUInt32();
module = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(modulePtr) as string;
file = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(filePtr) as string;
module = modulePtr.FromUtf8();
file = filePtr.FromUtf8();
}
}
......
......@@ -173,21 +173,30 @@ namespace LibVLCSharp.Shared
if (libVLC == null) throw new ArgumentNullException(nameof(libVLC));
if (string.IsNullOrEmpty(mrl)) throw new ArgumentNullException(nameof(mrl));
var mrlPtr = Utf8StringMarshaler.GetInstance().MarshalManagedToNative(mrl);
var mrlPtr = mrl.ToUtf8();
if (mrlPtr == IntPtr.Zero)
throw new ArgumentException($"error marshalling {mrl} to UTF-8 for native interop");
IntPtr result;
switch (type)
{
case FromType.FromLocation:
return Native.LibVLCMediaNewLocation(libVLC.NativeReference, mrlPtr);
result = Native.LibVLCMediaNewLocation(libVLC.NativeReference, mrlPtr);
break;
case FromType.FromPath:
return Native.LibVLCMediaNewPath(libVLC.NativeReference, mrlPtr);
result = Native.LibVLCMediaNewPath(libVLC.NativeReference, mrlPtr);
break;
case FromType.AsNode:
return Native.LibVLCMediaNewAsNode(libVLC.NativeReference, mrlPtr);
result = Native.LibVLCMediaNewAsNode(libVLC.NativeReference, mrlPtr);
break;
default:
return IntPtr.Zero;
result = IntPtr.Zero;
break;
}
Marshal.FreeHGlobal(mrlPtr);
return result;
}
/// <summary>
......@@ -234,7 +243,9 @@ namespace LibVLCSharp.Shared
{
foreach(var option in options)
{
Native.LibVLCMediaAddOption(NativeReference, Utf8StringMarshaler.GetInstance().MarshalManagedToNative(option));
var optionUtf8 = option.ToUtf8();
MarshalUtils.PerformInteropAndFree(() => Native.LibVLCMediaAddOption(NativeReference, optionUtf8), optionUtf8);
}
}
......@@ -327,7 +338,8 @@ namespace LibVLCSharp.Shared
if (string.IsNullOrEmpty(_mrl))
{
var mrlPtr = Native.LibVLCMediaGetMrl(NativeReference);
_mrl = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(mrlPtr) as string;
_mrl = mrlPtr.FromUtf8();
MarshalUtils.LibVLCFree(ref mrlPtr);
}
return _mrl;
}
......@@ -350,8 +362,7 @@ namespace LibVLCSharp.Shared
public string Meta(MetadataType metadataType)
{
var metaPtr = Native.LibVLCMediaGetMeta(NativeReference, metadataType);
if (metaPtr == IntPtr.Zero) return string.Empty;
return Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(metaPtr) as string;
return metaPtr.FromUtf8(libvlcFree: true);
}
/// <summary>
......
......@@ -73,8 +73,7 @@ namespace LibVLCSharp.Shared
/// Get media service discover object its localized name.
/// under v3 only
/// </summary>
public string LocalizedName => (string) Utf8StringMarshaler.GetInstance()
.MarshalNativeToManaged(Native.LibVLCMediaDiscovererLocalizedName(NativeReference));
public string LocalizedName => Native.LibVLCMediaDiscovererLocalizedName(NativeReference).FromUtf8();
/// <summary>
/// Get event manager from media service discover object.
......
......@@ -113,8 +113,6 @@ namespace LibVLCSharp.Shared
const int VideoRenderer = 0x0002;
const int AudioRenderer = 0x0001;
readonly Utf8StringMarshaler _utf8Marshaler = Utf8StringMarshaler.GetInstance();
readonly struct Native
{
[DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
......@@ -151,17 +149,17 @@ namespace LibVLCSharp.Shared
/// <summary>
/// Name of the renderer item
/// </summary>
public string Name => _utf8Marshaler.MarshalNativeToManaged(Native.LibVLCRendererItemName(NativeReference)) as string;
public string Name => Native.LibVLCRendererItemName(NativeReference).FromUtf8();
/// <summary>
/// Type of the renderer item
/// </summary>
public string Type => _utf8Marshaler.MarshalNativeToManaged(Native.LibVLCRendererItemType(NativeReference)) as string;
public string Type => Native.LibVLCRendererItemType(NativeReference).FromUtf8();
/// <summary>
/// IconUri of the renderer item
/// </summary>
public string IconUri => _utf8Marshaler.MarshalNativeToManaged(Native.LibVLCRendererItemIconUri(NativeReference)) as string;
public string IconUri => Native.LibVLCRendererItemIconUri(NativeReference).FromUtf8();
/// <summary>
/// true if the renderer item can render video
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment